diff options
31 files changed, 2171 insertions, 340 deletions
diff --git a/api/current.txt b/api/current.txt index 725f1f057c76..5795575545c3 100644 --- a/api/current.txt +++ b/api/current.txt @@ -114,6 +114,7 @@ package android { field public static final java.lang.String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH"; field public static final java.lang.String RECORD_AUDIO = "android.permission.RECORD_AUDIO"; field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS"; + field public static final java.lang.String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES"; field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES"; field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES"; @@ -362,6 +363,7 @@ package android { field public static final int centerMedium = 16842959; // 0x10100cf field public static final int centerX = 16843170; // 0x10101a2 field public static final int centerY = 16843171; // 0x10101a3 + field public static final int certDigest = 16844106; // 0x101054a field public static final int checkBoxPreferenceStyle = 16842895; // 0x101008f field public static final int checkMark = 16843016; // 0x1010108 field public static final int checkMarkTint = 16843943; // 0x10104a7 @@ -9935,6 +9937,7 @@ package android.content.pm { method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback); method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler); method public void uninstall(java.lang.String, android.content.IntentSender); + method public void uninstall(android.content.pm.VersionedPackage, android.content.IntentSender); method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback); method public void updateSessionAppIcon(int, android.graphics.Bitmap); method public void updateSessionAppLabel(int, java.lang.CharSequence); @@ -10081,6 +10084,7 @@ package android.content.pm { method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; + method public abstract android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.PackageInstaller getPackageInstaller(); method public abstract int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract java.lang.String[] getPackagesForUid(int); @@ -10095,6 +10099,7 @@ package android.content.pm { method public abstract android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException; + method public abstract java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int); method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures(); method public abstract java.lang.String[] getSystemSharedLibraryNames(); method public abstract java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo); @@ -10253,6 +10258,7 @@ package android.content.pm { field public static final int SIGNATURE_UNKNOWN_PACKAGE = -4; // 0xfffffffc field public static final int VERIFICATION_ALLOW = 1; // 0x1 field public static final int VERIFICATION_REJECT = -1; // 0xffffffff + field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff } public static class PackageManager.NameNotFoundException extends android.util.AndroidException { @@ -10392,6 +10398,20 @@ package android.content.pm { field public java.lang.String permission; } + public final class SharedLibraryInfo implements android.os.Parcelable { + method public int describeContents(); + method public android.content.pm.VersionedPackage getDeclaringPackage(); + method public java.util.List<android.content.pm.VersionedPackage> getDependentPackages(); + method public java.lang.String getName(); + method public int getVersion(); + method public boolean isBuiltin(); + method public boolean isDynamic(); + method public boolean isStatic(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.content.pm.SharedLibraryInfo> CREATOR; + field public static final int VERSION_UNDEFINED = -1; // 0xffffffff + } + public final class ShortcutInfo implements android.os.Parcelable { method public int describeContents(); method public android.content.ComponentName getActivity(); @@ -10467,6 +10487,15 @@ package android.content.pm { field public static final android.os.Parcelable.Creator<android.content.pm.Signature> CREATOR; } + public final class VersionedPackage implements android.os.Parcelable { + ctor public VersionedPackage(java.lang.String, int); + method public int describeContents(); + method public java.lang.String getPackageName(); + method public long getVersionCode(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.content.pm.VersionedPackage> CREATOR; + } + } package android.content.res { @@ -39175,6 +39204,7 @@ package android.test.mock { method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; + method public android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.PackageInstaller getPackageInstaller(); method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public java.lang.String[] getPackagesForUid(int); @@ -39189,6 +39219,7 @@ package android.test.mock { method public android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo); method public android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException; + method public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int); method public android.content.pm.FeatureInfo[] getSystemAvailableFeatures(); method public java.lang.String[] getSystemSharedLibraryNames(); method public java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo); diff --git a/api/system-current.txt b/api/system-current.txt index 0b5040a847d1..37fca366450e 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -200,6 +200,7 @@ package android { field public static final java.lang.String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION"; field public static final java.lang.String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES"; field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS"; + field public static final java.lang.String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES"; field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES"; field public static final java.lang.String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES"; @@ -471,6 +472,7 @@ package android { field public static final int centerMedium = 16842959; // 0x10100cf field public static final int centerX = 16843170; // 0x10101a2 field public static final int centerY = 16843171; // 0x10101a3 + field public static final int certDigest = 16844106; // 0x101054a field public static final int checkBoxPreferenceStyle = 16842895; // 0x101008f field public static final int checkMark = 16843016; // 0x1010108 field public static final int checkMarkTint = 16843943; // 0x10104a7 @@ -10369,6 +10371,7 @@ package android.content.pm { method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback); method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler); method public void uninstall(java.lang.String, android.content.IntentSender); + method public void uninstall(android.content.pm.VersionedPackage, android.content.IntentSender); method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback); method public void updateSessionAppIcon(int, android.graphics.Bitmap); method public void updateSessionAppLabel(int, java.lang.CharSequence); @@ -10522,6 +10525,7 @@ package android.content.pm { method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; + method public abstract android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.PackageInstaller getPackageInstaller(); method public abstract int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract java.lang.String[] getPackagesForUid(int); @@ -10537,6 +10541,7 @@ package android.content.pm { method public abstract android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException; + method public abstract java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int); method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures(); method public abstract java.lang.String[] getSystemSharedLibraryNames(); method public abstract java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo); @@ -10752,6 +10757,7 @@ package android.content.pm { field public static final int SIGNATURE_UNKNOWN_PACKAGE = -4; // 0xfffffffc field public static final int VERIFICATION_ALLOW = 1; // 0x1 field public static final int VERIFICATION_REJECT = -1; // 0xffffffff + field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff } public static class PackageManager.NameNotFoundException extends android.util.AndroidException { @@ -10900,6 +10906,20 @@ package android.content.pm { field public java.lang.String permission; } + public final class SharedLibraryInfo implements android.os.Parcelable { + method public int describeContents(); + method public android.content.pm.VersionedPackage getDeclaringPackage(); + method public java.util.List<android.content.pm.VersionedPackage> getDependentPackages(); + method public java.lang.String getName(); + method public int getVersion(); + method public boolean isBuiltin(); + method public boolean isDynamic(); + method public boolean isStatic(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.content.pm.SharedLibraryInfo> CREATOR; + field public static final int VERSION_UNDEFINED = -1; // 0xffffffff + } + public final class ShortcutInfo implements android.os.Parcelable { method public int describeContents(); method public android.content.ComponentName getActivity(); @@ -10975,6 +10995,15 @@ package android.content.pm { field public static final android.os.Parcelable.Creator<android.content.pm.Signature> CREATOR; } + public final class VersionedPackage implements android.os.Parcelable { + ctor public VersionedPackage(java.lang.String, int); + method public int describeContents(); + method public java.lang.String getPackageName(); + method public long getVersionCode(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.content.pm.VersionedPackage> CREATOR; + } + } package android.content.pm.permission { @@ -42444,6 +42473,7 @@ package android.test.mock { method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; + method public android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.PackageInstaller getPackageInstaller(); method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public java.lang.String[] getPackagesForUid(int); @@ -42459,6 +42489,7 @@ package android.test.mock { method public android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo); method public android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException; + method public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int); method public android.content.pm.FeatureInfo[] getSystemAvailableFeatures(); method public java.lang.String[] getSystemSharedLibraryNames(); method public java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo); diff --git a/api/test-current.txt b/api/test-current.txt index f5212327900a..66071a2764bc 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -114,6 +114,7 @@ package android { field public static final java.lang.String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH"; field public static final java.lang.String RECORD_AUDIO = "android.permission.RECORD_AUDIO"; field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS"; + field public static final java.lang.String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES"; field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES"; field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES"; @@ -362,6 +363,7 @@ package android { field public static final int centerMedium = 16842959; // 0x10100cf field public static final int centerX = 16843170; // 0x10101a2 field public static final int centerY = 16843171; // 0x10101a3 + field public static final int certDigest = 16844106; // 0x101054a field public static final int checkBoxPreferenceStyle = 16842895; // 0x101008f field public static final int checkMark = 16843016; // 0x1010108 field public static final int checkMarkTint = 16843943; // 0x10104a7 @@ -9963,6 +9965,7 @@ package android.content.pm { method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback); method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler); method public void uninstall(java.lang.String, android.content.IntentSender); + method public void uninstall(android.content.pm.VersionedPackage, android.content.IntentSender); method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback); method public void updateSessionAppIcon(int, android.graphics.Bitmap); method public void updateSessionAppLabel(int, java.lang.CharSequence); @@ -10111,6 +10114,7 @@ package android.content.pm { method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; + method public abstract android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.PackageInstaller getPackageInstaller(); method public abstract int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract java.lang.String[] getPackagesForUid(int); @@ -10125,6 +10129,7 @@ package android.content.pm { method public abstract android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException; + method public abstract java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int); method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures(); method public abstract java.lang.String[] getSystemSharedLibraryNames(); method public abstract java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo); @@ -10283,6 +10288,7 @@ package android.content.pm { field public static final int SIGNATURE_UNKNOWN_PACKAGE = -4; // 0xfffffffc field public static final int VERIFICATION_ALLOW = 1; // 0x1 field public static final int VERIFICATION_REJECT = -1; // 0xffffffff + field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff } public static class PackageManager.NameNotFoundException extends android.util.AndroidException { @@ -10423,6 +10429,20 @@ package android.content.pm { field public java.lang.String permission; } + public final class SharedLibraryInfo implements android.os.Parcelable { + method public int describeContents(); + method public android.content.pm.VersionedPackage getDeclaringPackage(); + method public java.util.List<android.content.pm.VersionedPackage> getDependentPackages(); + method public java.lang.String getName(); + method public int getVersion(); + method public boolean isBuiltin(); + method public boolean isDynamic(); + method public boolean isStatic(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.content.pm.SharedLibraryInfo> CREATOR; + field public static final int VERSION_UNDEFINED = -1; // 0xffffffff + } + public final class ShortcutInfo implements android.os.Parcelable { method public int describeContents(); method public android.content.ComponentName getActivity(); @@ -10499,6 +10519,15 @@ package android.content.pm { field public static final android.os.Parcelable.Creator<android.content.pm.Signature> CREATOR; } + public final class VersionedPackage implements android.os.Parcelable { + ctor public VersionedPackage(java.lang.String, int); + method public int describeContents(); + method public java.lang.String getPackageName(); + method public long getVersionCode(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.content.pm.VersionedPackage> CREATOR; + } + } package android.content.res { @@ -39299,6 +39328,7 @@ package android.test.mock { method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; + method public android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.PackageInstaller getPackageInstaller(); method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public java.lang.String[] getPackagesForUid(int); @@ -39313,6 +39343,7 @@ package android.test.mock { method public android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo); method public android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException; + method public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int); method public android.content.pm.FeatureInfo[] getSystemAvailableFeatures(); method public java.lang.String[] getSystemSharedLibraryNames(); method public java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo); diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 810d20187ee4..ac5fea36ad2b 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -1556,7 +1556,7 @@ public final class Pm { System.err.println(" pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH]"); System.err.println(" pm install-commit SESSION_ID"); System.err.println(" pm install-abandon SESSION_ID"); - System.err.println(" pm uninstall [-k] [--user USER_ID] PACKAGE"); + System.err.println(" pm uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE] PACKAGE"); System.err.println(" pm set-installer PACKAGE INSTALLER"); System.err.println(" pm move-package PACKAGE [internal|UUID]"); System.err.println(" pm move-primary-storage [internal|UUID]"); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 20f7e63e4d77..f790542c6847 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -17,11 +17,11 @@ package android.app; import android.annotation.DrawableRes; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; import android.annotation.XmlRes; -import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -53,13 +53,13 @@ import android.content.pm.PermissionInfo; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.content.pm.UserInfo; +import android.content.pm.SharedLibraryInfo; import android.content.pm.VerifierDeviceIdentity; +import android.content.pm.VersionedPackage; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.Bitmap; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; @@ -137,6 +137,21 @@ public class ApplicationPackageManager extends PackageManager { } @Override + public PackageInfo getPackageInfo(VersionedPackage versionedPackage, int flags) + throws NameNotFoundException { + try { + PackageInfo pi = mPM.getPackageInfoVersioned(versionedPackage, flags, + mContext.getUserId()); + if (pi != null) { + return pi; + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + throw new NameNotFoundException(versionedPackage.toString()); + } + + @Override public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId) throws NameNotFoundException { try { @@ -147,7 +162,6 @@ public class ApplicationPackageManager extends PackageManager { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - throw new NameNotFoundException(packageName); } @@ -445,6 +459,28 @@ public class ApplicationPackageManager extends PackageManager { /** @hide */ @Override + public @NonNull List<SharedLibraryInfo> getSharedLibraries(int flags) { + return getSharedLibrariesAsUser(flags, mContext.getUserId()); + } + + /** @hide */ + @Override + @SuppressWarnings("unchecked") + public @NonNull List<SharedLibraryInfo> getSharedLibrariesAsUser(int flags, int userId) { + try { + ParceledListSlice<SharedLibraryInfo> sharedLibs = mPM.getSharedLibraries( + flags, userId); + if (sharedLibs == null) { + return Collections.emptyList(); + } + return sharedLibs.getList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** @hide */ + @Override public @NonNull String getServicesSystemSharedLibraryPackageName() { try { return mPM.getServicesSystemSharedLibraryPackageName(); @@ -1977,10 +2013,11 @@ public class ApplicationPackageManager extends PackageManager { } @Override - public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int flags, - int userId) { + public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, + int flags, int userId) { try { - mPM.deletePackageAsUser(packageName, observer, userId, flags); + mPM.deletePackageAsUser(packageName, PackageManager.VERSION_CODE_HIGHEST, + observer, userId, flags); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2303,7 +2340,7 @@ public class ApplicationPackageManager extends PackageManager { synchronized (mLock) { if (mInstaller == null) { try { - mInstaller = new PackageInstaller(mContext, this, mPM.getPackageInstaller(), + mInstaller = new PackageInstaller(mPM.getPackageInstaller(), mContext.getPackageName(), mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 71071e1d45ad..04ab2394b0d1 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -551,6 +551,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int PRIVATE_FLAG_BACKUP_IN_FOREGROUND = 1 << 12; /** + * Value for {@link #privateFlags}: {@code true} means this application + * contains a static shared library. Defaults to {@code false} if unspecified. + * @hide + */ + public static final int PRIVATE_FLAG_STATIC_SHARED_LIBRARY = 1 << 13; + + /** * Private/hidden flags. See {@code PRIVATE_FLAG_...} constants. * {@hide} */ @@ -1358,6 +1365,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { /** * @hide */ + public boolean isStaticSharedLibrary() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY) != 0; + } + + /** + * @hide + */ @Override protected ApplicationInfo getApplicationInfo() { return this; } diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index 154ff85b0113..ecc8cd678af1 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -21,6 +21,7 @@ import android.content.pm.IPackageInstallerCallback; import android.content.pm.IPackageInstallerSession; import android.content.pm.PackageInstaller; import android.content.pm.ParceledListSlice; +import android.content.pm.VersionedPackage; import android.content.IntentSender; import android.graphics.Bitmap; @@ -44,7 +45,7 @@ interface IPackageInstaller { void registerCallback(IPackageInstallerCallback callback, int userId); void unregisterCallback(IPackageInstallerCallback callback); - void uninstall(String packageName, String callerPackageName, int flags, + void uninstall(in VersionedPackage versionedPackage, String callerPackageName, int flags, in IntentSender statusReceiver, int userId); void setPermissionsResult(int sessionId, boolean accepted); diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 01f4e00210bd..ab9af5abdb67 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -47,6 +47,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; +import android.content.pm.VersionedPackage; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; @@ -63,6 +64,8 @@ interface IPackageManager { void checkPackageStartable(String packageName, int userId); boolean isPackageAvailable(String packageName, int userId); PackageInfo getPackageInfo(String packageName, int flags, int userId); + PackageInfo getPackageInfoVersioned(in VersionedPackage versionedPackage, + int flags, int userId); int getPackageUid(String packageName, int flags, int userId); int[] getPackageGids(String packageName, int flags, int userId); @@ -231,18 +234,19 @@ interface IPackageManager { void setApplicationCategoryHint(String packageName, int categoryHint, String callerPackageName); /** @deprecated rawr, don't call AIDL methods directly! */ - void deletePackageAsUser(in String packageName, IPackageDeleteObserver observer, - int userId, int flags); + void deletePackageAsUser(in String packageName, int versionCode, + IPackageDeleteObserver observer, int userId, int flags); /** * Delete a package for a specific user. * - * @param packageName The fully qualified name of the package to delete. + * @param versionedPackage The package to delete. * @param observer a callback to use to notify when the package deletion in finished. * @param userId the id of the user for whom to delete the package * @param flags - possible values: {@link #DONT_DELETE_DATA} */ - void deletePackage(in String packageName, IPackageDeleteObserver2 observer, int userId, int flags); + void deletePackageVersioned(in VersionedPackage versionedPackage, + IPackageDeleteObserver2 observer, int userId, int flags); String getInstallerPackageName(in String packageName); @@ -588,4 +592,6 @@ interface IPackageManager { List<String> getPreviousCodePaths(in String packageName); int getInstallReason(String packageName, int userId); + + ParceledListSlice getSharedLibraries(int flags, int userId); } diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java index d40bab58ae77..5d5696b5a54e 100644 --- a/core/java/android/content/pm/PackageInfo.java +++ b/core/java/android/content/pm/PackageInfo.java @@ -142,7 +142,7 @@ public class PackageInfo implements Parcelable { * {@link PackageManager#GET_INSTRUMENTATION} was set. */ public InstrumentationInfo[] instrumentation; - + /** * Array of all {@link android.R.styleable#AndroidManifestPermission * <permission>} tags included under <manifest>, @@ -150,7 +150,7 @@ public class PackageInfo implements Parcelable { * {@link PackageManager#GET_PERMISSIONS} was set. */ public PermissionInfo[] permissions; - + /** * Array of all {@link android.R.styleable#AndroidManifestUsesPermission * <uses-permission>} tags included under <manifest>, @@ -160,7 +160,7 @@ public class PackageInfo implements Parcelable { * by the system at install time. */ public String[] requestedPermissions; - + /** * Array of flags of all {@link android.R.styleable#AndroidManifestUsesPermission * <uses-permission>} tags included under <manifest>, diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index db3f63708be4..4de967c50dcd 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -16,6 +16,7 @@ package android.content.pm; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -23,7 +24,6 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.app.ActivityManager; -import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.graphics.Bitmap; @@ -36,9 +36,11 @@ import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.os.RemoteException; +import android.annotation.IntRange; import android.util.ExceptionUtils; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.Preconditions; import java.io.Closeable; import java.io.IOException; @@ -256,8 +258,6 @@ public class PackageInstaller { */ public static final int STATUS_FAILURE_INCOMPATIBLE = 7; - private final Context mContext; - private final PackageManager mPm; private final IPackageInstaller mInstaller; private final int mUserId; private final String mInstallerPackageName; @@ -265,10 +265,8 @@ public class PackageInstaller { private final ArrayList<SessionCallbackDelegate> mDelegates = new ArrayList<>(); /** {@hide} */ - public PackageInstaller(Context context, PackageManager pm, IPackageInstaller installer, + public PackageInstaller(IPackageInstaller installer, String installerPackageName, int userId) { - mContext = context; - mPm = pm; mInstaller = installer; mInstallerPackageName = installerPackageName; mUserId = userId; @@ -413,10 +411,35 @@ public class PackageInstaller { * Uninstall the given package, removing it completely from the device. This * method is only available to the current "installer of record" for the * package. + * + * @param packageName The package to uninstall. + * @param statusReceiver Where to deliver the result. */ public void uninstall(@NonNull String packageName, @NonNull IntentSender statusReceiver) { + uninstall(new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), + statusReceiver); + } + + /** + * Uninstall the given package with a specific version code, removing it + * completely from the device. This method is only available to the current + * "installer of record" for the package. If the version code of the package + * does not match the one passed in the versioned package argument this + * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to + * uninstall the latest version of the package. + * + * @param versionedPackage The versioned package to uninstall. + * @param statusReceiver Where to deliver the result. + */ + @RequiresPermission(anyOf = { + Manifest.permission.DELETE_PACKAGES, + Manifest.permission.REQUEST_DELETE_PACKAGES}) + public void uninstall(@NonNull VersionedPackage versionedPackage, + @NonNull IntentSender statusReceiver) { + Preconditions.checkNotNull(versionedPackage, "versionedPackage cannot be null"); try { - mInstaller.uninstall(packageName, mInstallerPackageName, 0, statusReceiver, mUserId); + mInstaller.uninstall(versionedPackage, mInstallerPackageName, + 0, statusReceiver, mUserId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java index bc79f41b1fc1..11830c294116 100644 --- a/core/java/android/content/pm/PackageItemInfo.java +++ b/core/java/android/content/pm/PackageItemInfo.java @@ -24,14 +24,10 @@ import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Parcel; import android.os.UserHandle; -import android.text.BidiFormatter; import android.text.Html; import android.text.TextPaint; import android.text.TextUtils; import android.util.Printer; -import android.text.BidiFormatter; -import android.text.TextPaint; -import android.text.Html; import java.text.Collator; import java.util.Comparator; @@ -50,31 +46,31 @@ public class PackageItemInfo { * Public name of this item. From the "android:name" attribute. */ public String name; - + /** * Name of the package that this item is in. */ public String packageName; - + /** * A string resource identifier (in the package's resources) of this * component's label. From the "label" attribute or, if not set, 0. */ public int labelRes; - + /** * The string provided in the AndroidManifest file, if any. You * probably don't want to use this. You probably want * {@link PackageManager#getApplicationLabel} */ public CharSequence nonLocalizedLabel; - + /** * A drawable resource identifier (in the package's resources) of this * component's icon. From the "icon" attribute or, if not set, 0. */ public int icon; - + /** * A drawable resource identifier (in the package's resources) of this * component's banner. From the "banner" attribute or, if not set, 0. @@ -85,10 +81,10 @@ public class PackageItemInfo { * A drawable resource identifier (in the package's resources) of this * component's logo. Logos may be larger/wider than icons and are * displayed by certain UI elements in place of a name or name/icon - * combination. From the "logo" attribute or, if not set, 0. + * combination. From the "logo" attribute or, if not set, 0. */ public int logo; - + /** * Additional meta-data associated with this component. This field * will only be filled in if you set the @@ -124,10 +120,10 @@ public class PackageItemInfo { * Retrieve the current textual label associated with this item. This * will call back on the given PackageManager to load the label from * the application. - * + * * @param pm A PackageManager from which the label can be loaded; usually * the PackageManager from which you originally retrieved this item. - * + * * @return Returns a CharSequence containing the item's label. If the * item does not have a label, its name is returned. */ @@ -146,7 +142,7 @@ public class PackageItemInfo { } return packageName; } - + /** * Same as {@link #loadLabel(PackageManager)} with the addition that * the returned label is safe for being presented in the UI since it @@ -207,10 +203,10 @@ public class PackageItemInfo { * Retrieve the current graphical icon associated with this item. This * will call back on the given PackageManager to load the icon from * the application. - * + * * @param pm A PackageManager from which the icon can be loaded; usually * the PackageManager from which you originally retrieved this item. - * + * * @return Returns a Drawable containing the item's icon. If the * item does not have an icon, the item's default icon is returned * such as the default activity icon. @@ -259,13 +255,13 @@ public class PackageItemInfo { /** * Retrieve the default graphical icon associated with this item. - * + * * @param pm A PackageManager from which the icon can be loaded; usually * the PackageManager from which you originally retrieved this item. - * + * * @return Returns a Drawable containing the item's default icon * such as the default activity icon. - * + * * @hide */ public Drawable loadDefaultIcon(PackageManager pm) { @@ -291,10 +287,10 @@ public class PackageItemInfo { * Retrieve the current graphical logo associated with this item. This * will call back on the given PackageManager to load the logo from * the application. - * + * * @param pm A PackageManager from which the logo can be loaded; usually * the PackageManager from which you originally retrieved this item. - * + * * @return Returns a Drawable containing the item's logo. If the item * does not have a logo, this method will return null. */ @@ -307,31 +303,31 @@ public class PackageItemInfo { } return loadDefaultLogo(pm); } - + /** * Retrieve the default graphical logo associated with this item. - * + * * @param pm A PackageManager from which the logo can be loaded; usually * the PackageManager from which you originally retrieved this item. - * + * * @return Returns a Drawable containing the item's default logo * or null if no default logo is available. - * + * * @hide */ protected Drawable loadDefaultLogo(PackageManager pm) { return null; } - + /** * Load an XML resource attached to the meta-data of this item. This will * retrieved the name meta-data entry, and if defined call back on the * given PackageManager to load its XML file from the application. - * + * * @param pm A PackageManager from which the XML can be loaded; usually * the PackageManager from which you originally retrieved this item. * @param name Name of the meta-date you would like to load. - * + * * @return Returns an XmlPullParser you can use to parse the XML file * assigned as the given meta-data. If the meta-data name is not defined * or the XML resource could not be found, null is returned. @@ -373,11 +369,11 @@ public class PackageItemInfo { + " banner=0x" + Integer.toHexString(banner)); } } - + protected void dumpBack(Printer pw, String prefix) { // no back here } - + public void writeToParcel(Parcel dest, int parcelableFlags) { dest.writeString(name); dest.writeString(packageName); @@ -389,7 +385,7 @@ public class PackageItemInfo { dest.writeInt(banner); dest.writeInt(showUserIcon); } - + protected PackageItemInfo(Parcel source) { name = source.readString(); packageName = source.readString(); @@ -406,9 +402,9 @@ public class PackageItemInfo { /** * Get the ApplicationInfo for the application to which this item belongs, * if available, otherwise returns null. - * + * * @return Returns the ApplicationInfo of this item, or null if not known. - * + * * @hide */ protected ApplicationInfo getApplicationInfo() { diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 507608a5dced..7bdc56db5300 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -20,6 +20,7 @@ import android.Manifest; import android.annotation.CheckResult; import android.annotation.DrawableRes; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -1287,6 +1288,13 @@ public abstract class PackageManager { public static final int DELETE_FAILED_ABORTED = -5; /** + * Deletion failed return code: this is passed to the + * {@link IPackageDeleteObserver} if the system failed to delete the package + * because the packge is a shared library used by other installed packages. + * {@hide} */ + public static final int DELETE_FAILED_USED_SHARED_LIBRARY = -6; + + /** * Return code that is passed to the {@link IPackageMoveObserver} when the * package has been successfully moved by the system. * @@ -2624,6 +2632,11 @@ public abstract class PackageManager { public static final int NOTIFY_PACKAGE_USE_REASONS_COUNT = 8; /** + * Constant for specifying the highest installed package version code. + */ + public static final int VERSION_CODE_HIGHEST = -1; + + /** * Retrieve overall information about an application package that is * installed on the system. * @@ -2671,7 +2684,58 @@ public abstract class PackageManager { throws NameNotFoundException; /** - * @hide + * Retrieve overall information about an application package that is + * installed on the system. This method can be used for retrieving + * information about packages for which multiple versions can be + * installed at the time. Currently only packages hosting static shared + * libraries can have multiple installed versions. The method can also + * be used to get info for a package that has a single version installed + * by passing {@link #VERSION_CODE_HIGHEST} in the {@link VersionedPackage} + * constructor. + * + * @param versionedPackage The versioned packages for which to query. + * @param flags Additional option flags. Use any combination of + * {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS}, + * {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION}, + * {@link #GET_INTENT_FILTERS}, {@link #GET_META_DATA}, + * {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS}, + * {@link #GET_RECEIVERS}, {@link #GET_SERVICES}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #GET_SIGNATURES}, + * {@link #GET_URI_PERMISSION_PATTERNS}, {@link #GET_UNINSTALLED_PACKAGES}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * + * @return A PackageInfo object containing information about the + * package. If flag {@code MATCH_UNINSTALLED_PACKAGES} is set and if the + * package is not found in the list of installed applications, the + * package information is retrieved from the list of uninstalled + * applications (which includes installed applications as well as + * applications with data directory i.e. applications which had been + * deleted with {@code DONT_DELETE_DATA} flag set). + * @throws NameNotFoundException if a package with the given name cannot be + * found on the system. + * @see #GET_ACTIVITIES + * @see #GET_CONFIGURATIONS + * @see #GET_GIDS + * @see #GET_INSTRUMENTATION + * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA + * @see #GET_PERMISSIONS + * @see #GET_PROVIDERS + * @see #GET_RECEIVERS + * @see #GET_SERVICES + * @see #GET_SHARED_LIBRARY_FILES + * @see #GET_SIGNATURES + * @see #GET_URI_PERMISSION_PATTERNS + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_UNINSTALLED_PACKAGES + */ + public abstract PackageInfo getPackageInfo(VersionedPackage versionedPackage, + @PackageInfoFlags int flags) throws NameNotFoundException; + + /** * Retrieve overall information about an application package that is * installed on the system. * @@ -2715,6 +2779,8 @@ public abstract class PackageManager { * @see #MATCH_DISABLED_COMPONENTS * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS * @see #MATCH_UNINSTALLED_PACKAGES + * + * @hide */ @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS) public abstract PackageInfo getPackageInfoAsUser(String packageName, @@ -3705,6 +3771,37 @@ public abstract class PackageManager { public abstract String[] getSystemSharedLibraryNames(); /** + * Get a list of shared libraries on the device. + * + * @param flags To filter the libraries to return. + * @return The shared library list. + * + * @see #MATCH_FACTORY_ONLY + * @see #MATCH_KNOWN_PACKAGES + * @see #MATCH_ANY_USER + * @see #MATCH_UNINSTALLED_PACKAGES + */ + public abstract @NonNull List<SharedLibraryInfo> getSharedLibraries( + @InstallFlags int flags); + + /** + * Get a list of shared libraries on the device. + * + * @param flags To filter the libraries to return. + * @param userId The user to query for. + * @return The shared library list. + * + * @see #MATCH_FACTORY_ONLY + * @see #MATCH_KNOWN_PACKAGES + * @see #MATCH_ANY_USER + * @see #MATCH_UNINSTALLED_PACKAGES + * + * @hide + */ + public abstract @NonNull List<SharedLibraryInfo> getSharedLibrariesAsUser( + @InstallFlags int flags, @UserIdInt int userId); + + /** * Get the name of the package hosting the services shared library. * * @return The library host package. @@ -5088,6 +5185,7 @@ public abstract class PackageManager { * indicate that no callback is desired. * @hide */ + @RequiresPermission(Manifest.permission.DELETE_PACKAGES) public abstract void deletePackage(String packageName, IPackageDeleteObserver observer, @DeleteFlags int flags); @@ -5106,11 +5204,11 @@ public abstract class PackageManager { * @param userId The user Id * @hide */ - @RequiresPermission(anyOf = { + @RequiresPermission(anyOf = { Manifest.permission.DELETE_PACKAGES, Manifest.permission.INTERACT_ACROSS_USERS_FULL}) - public abstract void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, - @DeleteFlags int flags, @UserIdInt int userId); + public abstract void deletePackageAsUser(@NonNull String packageName, + IPackageDeleteObserver observer, @DeleteFlags int flags, @UserIdInt int userId); /** * Retrieve the package name of the application that installed a package. This identifies @@ -5851,6 +5949,7 @@ public abstract class PackageManager { case DELETE_FAILED_USER_RESTRICTED: return "DELETE_FAILED_USER_RESTRICTED"; case DELETE_FAILED_OWNER_BLOCKED: return "DELETE_FAILED_OWNER_BLOCKED"; case DELETE_FAILED_ABORTED: return "DELETE_FAILED_ABORTED"; + case DELETE_FAILED_USED_SHARED_LIBRARY: return "DELETE_FAILED_USED_SHARED_LIBRARY"; default: return Integer.toString(status); } } @@ -5864,6 +5963,7 @@ public abstract class PackageManager { case DELETE_FAILED_USER_RESTRICTED: return PackageInstaller.STATUS_FAILURE_BLOCKED; case DELETE_FAILED_OWNER_BLOCKED: return PackageInstaller.STATUS_FAILURE_BLOCKED; case DELETE_FAILED_ABORTED: return PackageInstaller.STATUS_FAILURE_ABORTED; + case DELETE_FAILED_USED_SHARED_LIBRARY: return PackageInstaller.STATUS_FAILURE_CONFLICT; default: return PackageInstaller.STATUS_FAILURE; } } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 5dd77ee92d30..d8d7abe6360a 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1373,6 +1373,11 @@ public class PackageParser { "No APK Signature Scheme v2 signature in ephemeral package " + apkPath, e); } + // Static shared libraries must use only the V2 signing scheme + if (pkg.applicationInfo.isStaticSharedLibrary()) { + throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, + "Static shared libs must use v2 signature scheme " + apkPath); + } } catch (Exception e) { // APK Signature Scheme v2 signature was found but did not verify throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, @@ -2568,6 +2573,52 @@ public class PackageParser { return fi; } + private boolean parseUsesStaticLibrary(Package pkg, Resources res, XmlResourceParser parser, + String[] outError) throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, + com.android.internal.R.styleable.AndroidManifestUsesStaticLibrary); + + // Note: don't allow this value to be a reference to a resource that may change. + String lname = sa.getNonResourceString( + com.android.internal.R.styleable.AndroidManifestUsesLibrary_name); + final int version = sa.getInt( + com.android.internal.R.styleable.AndroidManifestUsesStaticLibrary_version, -1); + String certSha256 = sa.getNonResourceString(com.android.internal.R.styleable + .AndroidManifestUsesStaticLibrary_certDigest); + sa.recycle(); + + // Since an APK providing a static shared lib can only provide the lib - fail if malformed + if (lname == null || version < 0 || certSha256 == null) { + outError[0] = "Bad uses-static-library declaration name: " + lname + " version: " + + version + " certDigest" + certSha256; + mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; + XmlUtils.skipCurrentTag(parser); + return false; + } + + // Can depend only on one version of the same library + if (pkg.usesStaticLibraries != null && pkg.usesStaticLibraries.contains(lname)) { + outError[0] = "Depending on multiple versions of static library " + lname; + mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; + XmlUtils.skipCurrentTag(parser); + return false; + } + + lname = lname.intern(); + // We allow ":" delimiters in the SHA declaration as this is the format + // emitted by the certtool making it easy for developers to copy/paste. + certSha256 = certSha256.replace(":", "").toLowerCase(); + pkg.usesStaticLibraries = ArrayUtils.add(pkg.usesStaticLibraries, lname); + pkg.usesStaticLibrariesVersions = ArrayUtils.appendInt( + pkg.usesStaticLibrariesVersions, version); + pkg.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String.class, + pkg.usesStaticLibrariesCertDigests, certSha256); + + XmlUtils.skipCurrentTag(parser); + + return true; + } + private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser) throws XmlPullParserException, IOException { TypedArray sa = res.obtainAttributes(parser, @@ -3416,6 +3467,47 @@ public class PackageParser { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; } + } else if (tagName.equals("static-library")) { + sa = res.obtainAttributes(parser, + com.android.internal.R.styleable.AndroidManifestStaticLibrary); + + // Note: don't allow this value to be a reference to a resource + // that may change. + final String lname = sa.getNonResourceString( + com.android.internal.R.styleable.AndroidManifestStaticLibrary_name); + final int version = sa.getInt( + com.android.internal.R.styleable.AndroidManifestStaticLibrary_version, -1); + + sa.recycle(); + + // Since the app canot run without a static lib - fail if malformed + if (lname == null || version < 0) { + outError[0] = "Bad static-library declaration name: " + lname + + " version: " + version; + mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; + XmlUtils.skipCurrentTag(parser); + return false; + } + + if (owner.mSharedUserId != null) { + outError[0] = "sharedUserId not allowed in static shared library"; + mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID; + XmlUtils.skipCurrentTag(parser); + return false; + } + + if (owner.staticSharedLibName != null) { + outError[0] = "Multiple static-shared libs for package " + pkgName; + mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; + XmlUtils.skipCurrentTag(parser); + return false; + } + + owner.staticSharedLibName = lname.intern(); + owner.staticSharedLibVersion = version; + ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY; + + XmlUtils.skipCurrentTag(parser); } else if (tagName.equals("library")) { sa = res.obtainAttributes(parser, @@ -3431,12 +3523,18 @@ public class PackageParser { if (lname != null) { lname = lname.intern(); if (!ArrayUtils.contains(owner.libraryNames, lname)) { - owner.libraryNames = ArrayUtils.add(owner.libraryNames, lname); + owner.libraryNames = ArrayUtils.add( + owner.libraryNames, lname); } } XmlUtils.skipCurrentTag(parser); + } else if (tagName.equals("uses-static-library")) { + if (!parseUsesStaticLibrary(owner, res, parser, outError)) { + return false; + } + } else if (tagName.equals("uses-library")) { sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestUsesLibrary); @@ -3615,6 +3713,11 @@ public class PackageParser { return false; } + } else if (tagName.equals("uses-static-library")) { + if (!parseUsesStaticLibrary(owner, res, parser, outError)) { + return false; + } + } else if (tagName.equals("uses-library")) { sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestUsesLibrary); @@ -5187,6 +5290,10 @@ public class PackageParser { public String packageName; + // The package name declared in the manifest as the package can be + // renamed, for example static shared libs use synthetic package names. + public String manifestPackageName; + /** Names of any split APKs, ordered by parsed splitName */ public String[] splitNames; @@ -5241,8 +5348,13 @@ public class PackageParser { public Package parentPackage; public ArrayList<Package> childPackages; + public String staticSharedLibName = null; + public int staticSharedLibVersion = 0; public ArrayList<String> libraryNames = null; public ArrayList<String> usesLibraries = null; + public ArrayList<String> usesStaticLibraries = null; + public int[] usesStaticLibrariesVersions = null; + public String[] usesStaticLibrariesCertDigests = null; public ArrayList<String> usesOptionalLibraries = null; public String[] usesLibraryFiles = null; @@ -5341,6 +5453,7 @@ public class PackageParser { public Package(String packageName) { this.packageName = packageName; + this.manifestPackageName = packageName; applicationInfo.packageName = packageName; applicationInfo.uid = -1; } @@ -5659,6 +5772,7 @@ public class PackageParser { final ClassLoader boot = Object.class.getClassLoader(); packageName = dest.readString(); + manifestPackageName = dest.readString(); splitNames = dest.readStringArray(); volumeUuid = dest.readString(); codePath = dest.readString(); @@ -5699,11 +5813,23 @@ public class PackageParser { childPackages = null; } + staticSharedLibName = dest.readString(); + staticSharedLibVersion = dest.readInt(); libraryNames = dest.createStringArrayList(); usesLibraries = dest.createStringArrayList(); usesOptionalLibraries = dest.createStringArrayList(); usesLibraryFiles = dest.readStringArray(); + final int libCount = dest.readInt(); + if (libCount > 0) { + usesStaticLibraries = new ArrayList<>(libCount); + dest.readStringList(usesStaticLibraries); + usesStaticLibrariesVersions = new int[libCount]; + dest.readIntArray(usesStaticLibrariesVersions); + usesStaticLibrariesCertDigests = new String[libCount]; + dest.readStringArray(usesStaticLibrariesCertDigests); + } + preferredActivityFilters = new ArrayList<>(); dest.readParcelableList(preferredActivityFilters, boot); if (preferredActivityFilters.size() == 0) { @@ -5789,6 +5915,7 @@ public class PackageParser { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(packageName); + dest.writeString(manifestPackageName); dest.writeStringArray(splitNames); dest.writeString(volumeUuid); dest.writeString(codePath); @@ -5813,11 +5940,22 @@ public class PackageParser { dest.writeStringList(protectedBroadcasts); dest.writeParcelable(parentPackage, flags); dest.writeParcelableList(childPackages, flags); + dest.writeString(staticSharedLibName); + dest.writeInt(staticSharedLibVersion); dest.writeStringList(libraryNames); dest.writeStringList(usesLibraries); dest.writeStringList(usesOptionalLibraries); dest.writeStringArray(usesLibraryFiles); + if (ArrayUtils.isEmpty(usesStaticLibraries)) { + dest.writeInt(-1); + } else { + dest.writeInt(usesStaticLibraries.size()); + dest.writeStringList(usesStaticLibraries); + dest.writeIntArray(usesStaticLibrariesVersions); + dest.writeStringArray(usesStaticLibrariesCertDigests); + } + dest.writeParcelableList(preferredActivityFilters, flags); dest.writeStringList(mOriginalPackages); @@ -6239,6 +6377,9 @@ public class PackageParser { && p.usesLibraryFiles != null) { return true; } + if (p.staticSharedLibName != null) { + return true; + } return false; } diff --git a/core/java/android/content/pm/SharedLibraryInfo.aidl b/core/java/android/content/pm/SharedLibraryInfo.aidl new file mode 100644 index 000000000000..56d7c8325302 --- /dev/null +++ b/core/java/android/content/pm/SharedLibraryInfo.aidl @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.content.pm; + +parcelable SharedLibraryInfo; diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java new file mode 100644 index 000000000000..d79deb2b8459 --- /dev/null +++ b/core/java/android/content/pm/SharedLibraryInfo.java @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm; + +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Collections; +import java.util.List; + +/** + * This class provides information for a shared library. There are + * three types of shared libraries: builtin - non-updatable part of + * the OS; dynamic - updatable backwards-compatible dynamically linked; + * static - updatable non backwards-compatible emulating static linking. + */ +public final class SharedLibraryInfo implements Parcelable { + /** + * Shared library type: this library is a part of the OS + * and cannot be updated or uninstalled. + * @hide + */ + public static final int TYPE_BUILTIN = 0x1<<0; + + /** + * Shared library type: this library is backwards-compatible, can + * be updated, and updates can be uninstalled. Clients link against + * the latest version of the library. + * @hide + */ + public static final int TYPE_DYNAMIC = 0x1<<1; + + /** + * Shared library type: this library is <strong>not</strong> backwards + * -compatible, can be updated and updates can be uninstalled. Clients + * link against a specific version of the library. + * @hide + */ + public static final int TYPE_STATIC = 0x1<<2; + + /** + * Constant for referring to an undefined version. + */ + public static final int VERSION_UNDEFINED = -1; + + private final String mName; + private final int mVersion; + private final int mType; + private final VersionedPackage mDeclaringPackage; + private final List<VersionedPackage> mDependentPackages; + + /** + * Creates a new instance. + * + * @param name The lib name. + * @param version The lib version if not builtin. + * @param type The lib type. + * @param declaringPackage The package that declares the library. + * @param dependentPackages The packages that depend on the library. + * + * @hide + */ + public SharedLibraryInfo(String name, int version, int type, + VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages) { + mName = name; + mVersion = version; + mType = type; + mDeclaringPackage = declaringPackage; + mDependentPackages = dependentPackages; + } + + private SharedLibraryInfo(Parcel parcel) { + this(parcel.readString(), parcel.readInt(), parcel.readInt(), + parcel.readParcelable(null), parcel.readArrayList(null)); + } + + /** @hide */ + public int getType() { + return mType; + } + + /** + * Gets the library name. + * + * @return The name. + */ + public String getName() { + return mName; + } + + /** + * Gets the version of the library. For {@link #isStatic()} static} libraries + * this is the declared version and for {@link #isDynamic()} dynamic} and + * {@link #isBuiltin()} builtin} it is {@link #VERSION_UNDEFINED} as these + * are not versioned. + * + * @return The version. + */ + public @IntRange(from = -1) int getVersion() { + return mVersion; + } + + /** + * @return whether this library is builtin which means that it + * is a part of the OS and cannot be updated or uninstalled. + */ + public boolean isBuiltin() { + return mType == TYPE_BUILTIN; + } + + /** + * @return whether this library is dynamic which means that it + * is backwards-compatible, can be updated, and updates can be + * uninstalled. Clients link against the latest version of the + * library. + */ + public boolean isDynamic() { + return mType == TYPE_DYNAMIC; + } + + /** + * @return whether this library is dynamic which means that it + * is <strong>not</strong> backwards-compatible, can be updated + * and updates can be uninstalled. Clients link against a specific + * version of the library. + */ + public boolean isStatic() { + return mType == TYPE_STATIC; + } + + /** + * Gets the package that declares the library. + * + * @return The package declaring the library. + */ + public @NonNull VersionedPackage getDeclaringPackage() { + return mDeclaringPackage; + } + + /** + * Gets the packages that depend on the library. + * + * @return The dependent packages. + */ + public @NonNull List<VersionedPackage> getDependentPackages() { + if (mDependentPackages == null) { + return Collections.emptyList(); + } + return mDependentPackages; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public String toString() { + return "SharedLibraryInfo[name:" + mName + ", type:" + typeToString(mType) + + ", version:" + mVersion + (!getDependentPackages().isEmpty() + ? " has dependents" : ""); + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(mName); + parcel.writeInt(mVersion); + parcel.writeInt(mType); + parcel.writeParcelable(mDeclaringPackage, flags); + parcel.writeList(mDependentPackages); + } + + private static String typeToString(int type) { + switch (type) { + case TYPE_BUILTIN: { + return "builtin"; + } + case TYPE_DYNAMIC: { + return "dynamic"; + } + case TYPE_STATIC: { + return "static"; + } + default: { + return "unknown"; + } + } + } + + public static final Parcelable.Creator<SharedLibraryInfo> CREATOR = + new Parcelable.Creator<SharedLibraryInfo>() { + public SharedLibraryInfo createFromParcel(Parcel source) { + return new SharedLibraryInfo(source); + } + + public SharedLibraryInfo[] newArray(int size) { + return new SharedLibraryInfo[size]; + } + }; +} diff --git a/core/java/android/content/pm/VersionedPackage.aidl b/core/java/android/content/pm/VersionedPackage.aidl new file mode 100644 index 000000000000..43412a4722a5 --- /dev/null +++ b/core/java/android/content/pm/VersionedPackage.aidl @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.content.pm; + +parcelable VersionedPackage; diff --git a/core/java/android/content/pm/VersionedPackage.java b/core/java/android/content/pm/VersionedPackage.java new file mode 100644 index 000000000000..83e78152862e --- /dev/null +++ b/core/java/android/content/pm/VersionedPackage.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.content.pm; + +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Encapsulates a package and its version code. + */ +public final class VersionedPackage implements Parcelable { + private final String mPackageName; + private final long mVersionCode; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntRange(from = PackageManager.VERSION_CODE_HIGHEST) + public @interface VersionCode{} + + /** + * Creates a new instance. Use {@link PackageManager#VERSION_CODE_HIGHEST} + * to refer to the highest version code of this package. + * @param packageName The package name. + * @param versionCode The version code. + */ + public VersionedPackage(@NonNull String packageName, + @VersionCode int versionCode) { + mPackageName = packageName; + mVersionCode = versionCode; + } + + private VersionedPackage(Parcel parcel) { + mPackageName = parcel.readString(); + mVersionCode = parcel.readLong(); + } + + /** + * Gets the package name. + * + * @return The package name. + */ + public @NonNull String getPackageName() { + return mPackageName; + } + + /** + * Gets the version code. + * + * @return The version code. + */ + public @VersionCode long getVersionCode() { + return mVersionCode; + } + + @Override + public String toString() { + return "VersionedPackage[" + mPackageName + "/" + mVersionCode + "]"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(mPackageName); + parcel.writeLong(mVersionCode); + } + + public static final Creator<VersionedPackage> CREATOR = new Creator<VersionedPackage>() { + @Override + public VersionedPackage createFromParcel(Parcel source) { + return new VersionedPackage(source); + } + + @Override + public VersionedPackage[] newArray(int size) { + return new VersionedPackage[size]; + } + }; +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index db846c8dcdb9..2692bf2bce42 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2489,6 +2489,16 @@ android:description="@string/permdesc_requestInstallPackages" android:protectionLevel="signature|appop" /> + <!-- Allows an application to request deleting packages. Apps + targeting APIs greater than 25 must hold this permission in + order to use {@link android.content.Intent#ACTION_UNINSTALL_PACKAGE}. + <p>Protection level: normal + --> + <permission android:name="android.permission.REQUEST_DELETE_PACKAGES" + android:label="@string/permlab_requestDeletePackages" + android:description="@string/permdesc_requestDeletePackages" + android:protectionLevel="normal" /> + <!-- @SystemApi Allows an application to install packages. <p>Not for use by third-party applications. --> <permission android:name="android.permission.INSTALL_PACKAGES" @@ -3127,7 +3137,7 @@ <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/> - <!-- Allows the holder to access the ephemeral applications on the device. + <!-- Allows the holder to access the instant applications on the device. @hide --> <permission android:name="android.permission.ACCESS_EPHEMERAL_APPS" android:protectionLevel="signature" /> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 9b5603df8705..5235116f7a08 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1621,6 +1621,27 @@ <attr name="name" /> </declare-styleable> + + <!-- The <code>static-library</code> tag declares that this apk is providing itself + as a static shared library for other applications to use. Any app can declare such + a library and there can be only one static shared library per package. These libraries + are updatable, multiple versions can be installed at the same time, and an app links + against a specific version simulating static linking while allowing code sharing. + Other apks can link to it with the {@link #AndroidManifestUsesLibrary uses-static-library} + tag. + + <p>This appears as a child tag of the + {@link #AndroidManifestApplication application} tag. --> + <declare-styleable name="AndroidManifestStaticLibrary" parent="AndroidManifestApplication"> + <!-- Required public name of the library, which other components and + packages will use when referring to this library. This is a string using + Java-style scoping to ensure it is unique. The name should typically + be the same as the apk's package name. --> + <attr name="name" /> + <!-- Required specific library version. --> + <attr name="version" /> + </declare-styleable> + <!-- The <code>uses-libraries</code> specifies a shared library that this package requires to be linked against. Specifying this flag tells the system to include this library's code in your class loader. @@ -1640,6 +1661,24 @@ <attr name="required" /> </declare-styleable> + <!-- The <code>uses-static-library</code> specifies a shared <strong>static</strong> + library that this package requires to be statically linked against. Specifying + this tag tells the system to include this library's code in your class loader. + Depending on a static shared library is equivalent to statically linking with + the library at build time while it offers apps to share code defined in such + libraries. Hence, static libraries are strictly required. + + <p>This appears as a child tag of the + {@link #AndroidManifestApplication application} tag. --> + <declare-styleable name="AndroidManifestUsesStaticLibrary" parent="AndroidManifestApplication"> + <!-- Required name of the library you use. --> + <attr name="name" /> + <!-- Specify which version of the shared library should be statically linked. --> + <attr name="version" /> + <!-- The SHA-256 digest of the library signing certificate. --> + <attr name="certDigest" format="string" /> + </declare-styleable> + <!-- The <code>supports-screens</code> specifies the screen dimensions an application supports. By default a modern application supports all screen sizes and must explicitly disable certain screen sizes here; diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 44cd3385a0b9..060c59ed4a31 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2786,6 +2786,7 @@ <public name="autoSizeMaxTextSize" /> <public name="supportsDismissingWindow" /> <public name="restartOnConfigChanges" /> + <public name="certDigest" /> </public-group> <public-group type="style" first-id="0x010302e0"> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 3d497ccef7c5..d09b19069e77 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3190,6 +3190,11 @@ <!-- Description of an application permission that lets it read install sessions. --> <string name="permdesc_requestInstallPackages">Allows an application to request installation of packages.</string> + <!-- Title of an application permission that lets it read install sessions. --> + <string name="permlab_requestDeletePackages">request delete packages</string> + <!-- Description of an application permission that lets it read install sessions. --> + <string name="permdesc_requestDeletePackages">Allows an application to request deletion of packages.</string> + <!-- Title of an application permission that lets it ask user to ignore battery optimizations for that app. --> <string name="permlab_requestIgnoreBatteryOptimizations">ask to ignore battery optimizations</string> <!-- Description of an application permission that lets it ask user to ignore battery optimizations for that app--> diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index d516acfd0c66..da6a67e830b7 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -52,6 +52,7 @@ import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; +import android.content.pm.VersionedPackage; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; @@ -869,8 +870,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } @Override - public void uninstall(String packageName, String callerPackageName, int flags, - IntentSender statusReceiver, int userId) { + public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags, + IntentSender statusReceiver, int userId) throws RemoteException { final int callingUid = Binder.getCallingUid(); mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall"); if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) { @@ -884,24 +885,24 @@ public class PackageInstallerService extends IPackageInstaller.Stub { callerPackageName); final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext, - statusReceiver, packageName, isDeviceOwner, userId); + statusReceiver, versionedPackage.getPackageName(), isDeviceOwner, userId); if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES) == PackageManager.PERMISSION_GRANTED) { // Sweet, call straight through! - mPm.deletePackage(packageName, adapter.getBinder(), userId, flags); + mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags); } else if (isDeviceOwner) { // Allow the DeviceOwner to silently delete packages // Need to clear the calling identity to get DELETE_PACKAGES permission long ident = Binder.clearCallingIdentity(); try { - mPm.deletePackage(packageName, adapter.getBinder(), userId, flags); + mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags); } finally { Binder.restoreCallingIdentity(ident); } } else { // Take a short detour to confirm with user final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); - intent.setData(Uri.fromParts("package", packageName, null)); + intent.setData(Uri.fromParts("package", versionedPackage.getPackageName(), null)); intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder()); adapter.onUserActionRequired(intent); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e3fa0c4b2e1f..e40b30ff2556 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -16,7 +16,11 @@ package com.android.server.pm; +import static android.Manifest.permission.DELETE_PACKAGES; +import static android.Manifest.permission.INSTALL_PACKAGES; import static android.Manifest.permission.READ_EXTERNAL_STORAGE; +import static android.Manifest.permission.REQUEST_DELETE_PACKAGES; +import static android.Manifest.permission.REQUEST_INSTALL_PACKAGES; import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; import static android.Manifest.permission.WRITE_MEDIA_STORAGE; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; @@ -160,10 +164,12 @@ import android.content.pm.PermissionInfo; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.content.pm.SharedLibraryInfo; import android.content.pm.Signature; import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VerifierInfo; +import android.content.pm.VersionedPackage; import android.content.res.Resources; import android.graphics.Bitmap; import android.hardware.display.DisplayManager; @@ -218,6 +224,7 @@ import android.util.ExceptionUtils; import android.util.Log; import android.util.LogPrinter; import android.util.MathUtils; +import android.util.PackageUtils; import android.util.Pair; import android.util.PrintStreamPrinter; import android.util.Slog; @@ -415,6 +422,8 @@ public class PackageManagerService extends IPackageManager.Stub { static final int REMOVE_CHATTY = 1<<16; static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1<<17; + private static final String STATIC_SHARED_LIB_DELIMITER = "_"; + private static final int[] EMPTY_INT_ARRAY = new int[0]; /** @@ -710,16 +719,21 @@ public class PackageManagerService extends IPackageManager.Stub { public static final class SharedLibraryEntry { public final String path; public final String apk; + public final SharedLibraryInfo info; - SharedLibraryEntry(String _path, String _apk) { + SharedLibraryEntry(String _path, String _apk, String name, int version, int type, + String declaringPackageName, int declaringPackageVersionCode) { path = _path; apk = _apk; + info = new SharedLibraryInfo(name, version, type, new VersionedPackage( + declaringPackageName, declaringPackageVersionCode), null); } } // Currently known shared libraries. - final ArrayMap<String, SharedLibraryEntry> mSharedLibraries = - new ArrayMap<String, SharedLibraryEntry>(); + final ArrayMap<String, SparseArray<SharedLibraryEntry>> mSharedLibraries = new ArrayMap<>(); + final ArrayMap<String, SparseArray<SharedLibraryEntry>> mStaticLibsByDeclaringPackage = + new ArrayMap<>(); // All available activities, for your resolving pleasure. final ActivityIntentResolver mActivities = @@ -1763,7 +1777,8 @@ public class PackageManagerService extends IPackageManager.Stub { } // Send installed broadcasts if the install/update is not ephemeral - if (!isEphemeral(res.pkg)) { + // and the package is not a static shared lib. + if (!isEphemeral(res.pkg) && res.pkg.staticSharedLibName == null) { mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath); // Send added for users that see the package for the first time @@ -1940,9 +1955,10 @@ public class PackageManagerService extends IPackageManager.Stub { final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(fsUuid); for (PackageSetting ps : packages) { Slog.d(TAG, "Destroying " + ps.name + " because volume was forgotten"); - deletePackage(ps.name, new LegacyPackageDeleteObserver(null).getBinder(), + deletePackageVersioned(new VersionedPackage(ps.name, + PackageManager.VERSION_CODE_HIGHEST), + new LegacyPackageDeleteObserver(null).getBinder(), UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS); - // Try very hard to release any references to this package // so we don't risk the system server being killed due to // open FDs @@ -2251,9 +2267,12 @@ public class PackageManagerService extends IPackageManager.Stub { } ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries(); - for (int i=0; i<libConfig.size(); i++) { - mSharedLibraries.put(libConfig.keyAt(i), - new SharedLibraryEntry(libConfig.valueAt(i), null)); + final int builtInLibCount = libConfig.size(); + for (int i = 0; i < builtInLibCount; i++) { + String name = libConfig.keyAt(i); + String path = libConfig.valueAt(i); + addSharedLibraryLPw(path, null, name, SharedLibraryInfo.VERSION_UNDEFINED, + SharedLibraryInfo.TYPE_BUILTIN, PLATFORM_PACKAGE_NAME, 0); } mFoundPolicyFile = SELinuxMMAC.readInstallPolicy(); @@ -2318,32 +2337,38 @@ public class PackageManagerService extends IPackageManager.Stub { // to compile them only when we come across an app that uses them (there's // already logic for that in scanPackageLI) but that adds some complexity. for (String dexCodeInstructionSet : dexCodeInstructionSets) { - for (SharedLibraryEntry libEntry : mSharedLibraries.values()) { - final String lib = libEntry.path; - if (lib == null) { - continue; - } - - try { - // Shared libraries do not have profiles so we perform a full - // AOT compilation (if needed). - int dexoptNeeded = DexFile.getDexOptNeeded( - lib, dexCodeInstructionSet, - getCompilerFilterForReason(REASON_SHARED_APK), - false /* newProfile */); - if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { - mInstaller.dexopt(lib, Process.SYSTEM_UID, "*", - dexCodeInstructionSet, dexoptNeeded, null, - DEXOPT_PUBLIC, + final int libCount = mSharedLibraries.size(); + for (int i = 0; i < libCount; i++) { + SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i); + final int versionCount = versionedLib.size(); + for (int j = 0; j < versionCount; j++) { + SharedLibraryEntry libEntry = versionedLib.valueAt(j); + final String libPath = libEntry.path != null + ? libEntry.path : libEntry.apk; + if (libPath == null) { + continue; + } + try { + // Shared libraries do not have profiles so we perform a full + // AOT compilation (if needed). + int dexoptNeeded = DexFile.getDexOptNeeded( + libPath, dexCodeInstructionSet, getCompilerFilterForReason(REASON_SHARED_APK), - StorageManager.UUID_PRIVATE_INTERNAL, - SKIP_SHARED_LIBRARY_CHECK); + false /* newProfile */); + if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { + mInstaller.dexopt(libPath, Process.SYSTEM_UID, "*", + dexCodeInstructionSet, dexoptNeeded, null, + DEXOPT_PUBLIC, + getCompilerFilterForReason(REASON_SHARED_APK), + StorageManager.UUID_PRIVATE_INTERNAL, + SKIP_SHARED_LIBRARY_CHECK); + } + } catch (FileNotFoundException e) { + Slog.w(TAG, "Library not found: " + libPath); + } catch (IOException | InstallerException e) { + Slog.w(TAG, "Cannot dexopt " + libPath + "; is it an APK or JAR? " + + e.getMessage()); } - } catch (FileNotFoundException e) { - Slog.w(TAG, "Library not found: " + lib); - } catch (IOException | InstallerException e) { - Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? " - + e.getMessage()); } } } @@ -2637,7 +2662,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Now that we know all of the shared libraries, update all clients to have // the correct library paths. - updateAllSharedLibrariesLPw(); + updateAllSharedLibrariesLPw(null); for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) { // NOTE: We ignore potential failures here during a system scan (like @@ -2774,9 +2799,11 @@ public class PackageManagerService extends IPackageManager.Stub { mIntentFilterVerifier = new IntentVerifierProxy(mContext, mIntentFilterVerifierComponent); mServicesSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr( - PackageManager.SYSTEM_SHARED_LIBRARY_SERVICES); + PackageManager.SYSTEM_SHARED_LIBRARY_SERVICES, + SharedLibraryInfo.VERSION_UNDEFINED); mSharedSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr( - PackageManager.SYSTEM_SHARED_LIBRARY_SHARED); + PackageManager.SYSTEM_SHARED_LIBRARY_SHARED, + SharedLibraryInfo.VERSION_UNDEFINED); } else { mRequiredVerifierPackage = null; mRequiredInstallerPackage = null; @@ -2933,11 +2960,11 @@ public class PackageManagerService extends IPackageManager.Stub { throw new RuntimeException("There must be exactly one verifier; found " + matches); } - private @NonNull String getRequiredSharedLibraryLPr(String libraryName) { + private @NonNull String getRequiredSharedLibraryLPr(String name, int version) { synchronized (mPackages) { - SharedLibraryEntry libraryEntry = mSharedLibraries.get(libraryName); + SharedLibraryEntry libraryEntry = getSharedLibraryEntryLPr(name, version); if (libraryEntry == null) { - throw new IllegalStateException("Missing required shared library:" + libraryName); + throw new IllegalStateException("Missing required shared library:" + name); } return libraryEntry.apk; } @@ -3297,8 +3324,17 @@ public class PackageManagerService extends IPackageManager.Stub { flags |= MATCH_ANY_USER; } - return PackageParser.generatePackageInfo(p, gids, flags, + PackageInfo packageInfo = PackageParser.generatePackageInfo(p, gids, flags, ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId); + + if (packageInfo == null) { + return null; + } + + packageInfo.packageName = packageInfo.applicationInfo.packageName = + resolveExternalPackageNameLPr(p); + + return packageInfo; } @Override @@ -3353,6 +3389,20 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public PackageInfo getPackageInfo(String packageName, int flags, int userId) { + return getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST, + flags, userId); + } + + @Override + public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage, + int flags, int userId) { + return getPackageInfoInternal(versionedPackage.getPackageName(), + // TODO: We will change version code to long, so in the new API it is long + (int) versionedPackage.getVersionCode(), flags, userId); + } + + private PackageInfo getPackageInfoInternal(String packageName, int versionCode, + int flags, int userId) { if (!sUserManager.exists(userId)) return null; flags = updateFlagsForPackage(flags, userId, packageName); enforceCrossUserPermission(Binder.getCallingUid(), userId, @@ -3360,16 +3410,20 @@ public class PackageManagerService extends IPackageManager.Stub { // reader synchronized (mPackages) { - // Normalize package name to handle renamed packages - packageName = normalizePackageNameLPr(packageName); + // Normalize package name to handle renamed packages and static libs + packageName = resolveInternalPackageNameLPr(packageName, versionCode); final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0; if (matchFactoryOnly) { final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName); if (ps != null) { + if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) { + return null; + } return generatePackageInfo(ps, flags, userId); } } + PackageParser.Package p = mPackages.get(packageName); if (matchFactoryOnly && p != null && !isSystemApp(p)) { return null; @@ -3377,16 +3431,68 @@ public class PackageManagerService extends IPackageManager.Stub { if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getPackageInfo " + packageName + ": " + p); if (p != null) { + if (filterSharedLibPackageLPr((PackageSetting) p.mExtras, + Binder.getCallingUid(), userId)) { + return null; + } return generatePackageInfo((PackageSetting)p.mExtras, flags, userId); } if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) { final PackageSetting ps = mSettings.mPackages.get(packageName); + if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) { + return null; + } return generatePackageInfo(ps, flags, userId); } } return null; } + + private boolean filterSharedLibPackageLPr(PackageSetting ps, int uid, int userId) { + // System/shell/root get to see all static libs + final int appId = UserHandle.getAppId(uid); + if (appId == Process.SYSTEM_UID || appId == Process.SHELL_UID + || appId == Process.ROOT_UID) { + return false; + } + + // No package means no static lib as it is always on internal storage + if (ps.pkg == null || !ps.pkg.applicationInfo.isStaticSharedLibrary()) { + return false; + } + + final SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(ps.pkg.staticSharedLibName, + ps.pkg.staticSharedLibVersion); + if (libEntry == null) { + return false; + } + + final int resolvedUid = UserHandle.getUid(userId, UserHandle.getAppId(uid)); + final String[] uidPackageNames = getPackagesForUid(resolvedUid); + if (uidPackageNames == null) { + return true; + } + + for (String uidPackageName : uidPackageNames) { + if (ps.name.equals(uidPackageName)) { + return false; + } + PackageSetting uidPs = mSettings.getPackageLPr(uidPackageName); + if (uidPs != null) { + final int index = ArrayUtils.indexOf(uidPs.usesStaticLibraries, + libEntry.info.getName()); + if (index < 0) { + continue; + } + if (uidPs.pkg.usesStaticLibrariesVersions[index] == libEntry.info.getVersion()) { + return false; + } + } + } + return true; + } + @Override public String[] currentToCanonicalPackageNames(String[] names) { String[] out = new String[names.length]; @@ -3539,10 +3645,13 @@ public class PackageManagerService extends IPackageManager.Stub { } private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags, - int userId) { + int uid, int userId) { if (!sUserManager.exists(userId)) return null; PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { + if (filterSharedLibPackageLPr(ps, uid, userId)) { + return null; + } if (ps.pkg == null) { final PackageInfo pInfo = generatePackageInfo(ps, flags, userId); if (pInfo != null) { @@ -3550,8 +3659,12 @@ public class PackageManagerService extends IPackageManager.Stub { } return null; } - return PackageParser.generateApplicationInfo(ps.pkg, flags, + ApplicationInfo ai = PackageParser.generateApplicationInfo(ps.pkg, flags, ps.readUserState(userId), userId); + if (ai != null) { + ai.packageName = resolveExternalPackageNameLPr(ps.pkg); + } + return ai; } return null; } @@ -3565,8 +3678,9 @@ public class PackageManagerService extends IPackageManager.Stub { // writer synchronized (mPackages) { - // Normalize package name to hanlde renamed packages - packageName = normalizePackageNameLPr(packageName); + // Normalize package name to handle renamed packages and static libs + packageName = resolveInternalPackageNameLPr(packageName, + PackageManager.VERSION_CODE_HIGHEST); PackageParser.Package p = mPackages.get(packageName); if (DEBUG_PACKAGE_INFO) Log.v( @@ -3575,15 +3689,24 @@ public class PackageManagerService extends IPackageManager.Stub { if (p != null) { PackageSetting ps = mSettings.mPackages.get(packageName); if (ps == null) return null; + if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) { + return null; + } // Note: isEnabledLP() does not apply here - always return info - return PackageParser.generateApplicationInfo( + ApplicationInfo ai = PackageParser.generateApplicationInfo( p, flags, ps.readUserState(userId), userId); + if (ai != null) { + ai.packageName = resolveExternalPackageNameLPr(p); + } + return ai; } if ("android".equals(packageName)||"system".equals(packageName)) { return mAndroidApplication; } if ((flags & MATCH_KNOWN_PACKAGES) != 0) { - return generateApplicationInfoFromSettingsLPw(packageName, flags, userId); + // Already generates the external package name + return generateApplicationInfoFromSettingsLPw(packageName, + Binder.getCallingUid(), flags, userId); } } return null; @@ -3869,6 +3992,113 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override + public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(int flags, int userId) { + if (!sUserManager.exists(userId)) return null; + Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0"); + + flags = updateFlagsForPackage(flags, userId, null); + + final boolean canSeeStaticLibraries = + mContext.checkCallingOrSelfPermission(INSTALL_PACKAGES) + == PERMISSION_GRANTED + || mContext.checkCallingOrSelfPermission(DELETE_PACKAGES) + == PERMISSION_GRANTED + || mContext.checkCallingOrSelfPermission(REQUEST_INSTALL_PACKAGES) + == PERMISSION_GRANTED + || mContext.checkCallingOrSelfPermission(REQUEST_DELETE_PACKAGES) + == PERMISSION_GRANTED; + + synchronized (mPackages) { + List<SharedLibraryInfo> result = null; + + final int libCount = mSharedLibraries.size(); + for (int i = 0; i < libCount; i++) { + SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i); + if (versionedLib == null) { + continue; + } + + final int versionCount = versionedLib.size(); + for (int j = 0; j < versionCount; j++) { + SharedLibraryInfo libInfo = versionedLib.valueAt(j).info; + if (!canSeeStaticLibraries && libInfo.isStatic()) { + break; + } + final long identity = Binder.clearCallingIdentity(); + try { + // TODO: We will change version code to long, so in the new API it is long + PackageInfo packageInfo = getPackageInfoVersioned( + libInfo.getDeclaringPackage(), flags, userId); + if (packageInfo == null) { + continue; + } + } finally { + Binder.restoreCallingIdentity(identity); + } + + SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getName(), + libInfo.getVersion(), libInfo.getType(), libInfo.getDeclaringPackage(), + getPackagesUsingSharedLibraryLPr(libInfo, flags, userId)); + + if (result == null) { + result = new ArrayList<>(); + } + result.add(resLibInfo); + } + } + + return result != null ? new ParceledListSlice<>(result) : null; + } + } + + private List<VersionedPackage> getPackagesUsingSharedLibraryLPr( + SharedLibraryInfo libInfo, int flags, int userId) { + List<VersionedPackage> versionedPackages = null; + final int packageCount = mSettings.mPackages.size(); + for (int i = 0; i < packageCount; i++) { + PackageSetting ps = mSettings.mPackages.valueAt(i); + + if (ps == null) { + continue; + } + + if (!ps.getUserState().get(userId).isAvailable(flags)) { + continue; + } + + final String libName = libInfo.getName(); + if (libInfo.isStatic()) { + final int libIdx = ArrayUtils.indexOf(ps.usesStaticLibraries, libName); + if (libIdx < 0) { + continue; + } + if (ps.usesStaticLibrariesVersions[libIdx] != libInfo.getVersion()) { + continue; + } + if (versionedPackages == null) { + versionedPackages = new ArrayList<>(); + } + // If the dependent is a static shared lib, use the public package name + String dependentPackageName = ps.name; + if (ps.pkg != null && ps.pkg.applicationInfo.isStaticSharedLibrary()) { + dependentPackageName = ps.pkg.manifestPackageName; + } + versionedPackages.add(new VersionedPackage(dependentPackageName, ps.versionCode)); + } else if (ps.pkg != null) { + if (ArrayUtils.contains(ps.pkg.usesLibraries, libName) + || ArrayUtils.contains(ps.pkg.usesOptionalLibraries, libName)) { + if (versionedPackages == null) { + versionedPackages = new ArrayList<>(); + } + versionedPackages.add(new VersionedPackage(ps.name, ps.versionCode)); + } + } + } + + return versionedPackages; + } + + @Override public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) { if (!sUserManager.exists(userId)) return null; flags = updateFlagsForComponent(flags, userId, component); @@ -3910,17 +4140,44 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public String[] getSystemSharedLibraryNames() { - Set<String> libSet; synchronized (mPackages) { - libSet = mSharedLibraries.keySet(); - int size = libSet.size(); - if (size > 0) { - String[] libs = new String[size]; - libSet.toArray(libs); - return libs; + Set<String> libs = null; + final int libCount = mSharedLibraries.size(); + for (int i = 0; i < libCount; i++) { + SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i); + if (versionedLib == null) { + continue; + } + final int versionCount = versionedLib.size(); + for (int j = 0; j < versionCount; j++) { + SharedLibraryEntry libEntry = versionedLib.valueAt(j); + if (!libEntry.info.isStatic()) { + if (libs == null) { + libs = new ArraySet<>(); + } + libs.add(libEntry.info.getName()); + break; + } + PackageSetting ps = mSettings.getPackageLPr(libEntry.apk); + if (ps != null && !filterSharedLibPackageLPr(ps, Binder.getCallingUid(), + UserHandle.getUserId(Binder.getCallingUid()))) { + if (libs == null) { + libs = new ArraySet<>(); + } + libs.add(libEntry.info.getName()); + break; + } + } } + + if (libs != null) { + String[] libsArray = new String[libs.size()]; + libs.toArray(libsArray); + return libsArray; + } + + return null; } - return null; } @Override @@ -5032,7 +5289,9 @@ public class PackageManagerService extends IPackageManager.Stub { return res; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; - return new String[] { ps.name }; + if (ps.getInstalled(userId)) { + return new String[]{ps.name}; + } } } return null; @@ -6600,30 +6859,32 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { ArrayList<PackageInfo> list; if (listUninstalled) { - list = new ArrayList<PackageInfo>(mSettings.mPackages.size()); + list = new ArrayList<>(mSettings.mPackages.size()); for (PackageSetting ps : mSettings.mPackages.values()) { - final PackageInfo pi; - if (ps.pkg != null) { - pi = generatePackageInfo(ps, flags, userId); - } else { - pi = generatePackageInfo(ps, flags, userId); + if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) { + continue; } + final PackageInfo pi = generatePackageInfo(ps, flags, userId); if (pi != null) { list.add(pi); } } } else { - list = new ArrayList<PackageInfo>(mPackages.size()); + list = new ArrayList<>(mPackages.size()); for (PackageParser.Package p : mPackages.values()) { - final PackageInfo pi = - generatePackageInfo((PackageSetting)p.mExtras, flags, userId); + if (filterSharedLibPackageLPr((PackageSetting) p.mExtras, + Binder.getCallingUid(), userId)) { + continue; + } + final PackageInfo pi = generatePackageInfo((PackageSetting) + p.mExtras, flags, userId); if (pi != null) { list.add(pi); } } } - return new ParceledListSlice<PackageInfo>(list); + return new ParceledListSlice<>(list); } } @@ -6643,12 +6904,8 @@ public class PackageManagerService extends IPackageManager.Stub { if (numMatch == 0) { return; } - final PackageInfo pi; - if (ps.pkg != null) { - pi = generatePackageInfo(ps, flags, userId); - } else { - pi = generatePackageInfo(ps, flags, userId); - } + final PackageInfo pi = generatePackageInfo(ps, flags, userId); + // The above might return null in cases of uninstalled apps or install-state // skew across users/profiles. if (pi != null) { @@ -6713,7 +6970,7 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { ArrayList<ApplicationInfo> list; if (listUninstalled) { - list = new ArrayList<ApplicationInfo>(mSettings.mPackages.size()); + list = new ArrayList<>(mSettings.mPackages.size()); for (PackageSetting ps : mSettings.mPackages.values()) { ApplicationInfo ai; int effectiveFlags = flags; @@ -6721,30 +6978,43 @@ public class PackageManagerService extends IPackageManager.Stub { effectiveFlags |= PackageManager.MATCH_ANY_USER; } if (ps.pkg != null) { + if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) { + continue; + } ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags, ps.readUserState(userId), userId); + if (ai != null) { + ai.packageName = resolveExternalPackageNameLPr(ps.pkg); + } } else { - ai = generateApplicationInfoFromSettingsLPw(ps.name, effectiveFlags, - userId); + // Shared lib filtering done in generateApplicationInfoFromSettingsLPw + // and already converts to externally visible package name + ai = generateApplicationInfoFromSettingsLPw(ps.name, + Binder.getCallingUid(), effectiveFlags, userId); } if (ai != null) { list.add(ai); } } } else { - list = new ArrayList<ApplicationInfo>(mPackages.size()); + list = new ArrayList<>(mPackages.size()); for (PackageParser.Package p : mPackages.values()) { if (p.mExtras != null) { + PackageSetting ps = (PackageSetting) p.mExtras; + if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) { + continue; + } ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags, - ((PackageSetting)p.mExtras).readUserState(userId), userId); + ps.readUserState(userId), userId); if (ai != null) { + ai.packageName = resolveExternalPackageNameLPr(p); list.add(ai); } } } } - return new ParceledListSlice<ApplicationInfo>(list); + return new ParceledListSlice<>(list); } } @@ -6834,6 +7104,7 @@ public class PackageManagerService extends IPackageManager.Stub { mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_EPHEMERAL_APPS, "getEphemeralApplicationIcon"); + enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */, false /* checkShell */, "getEphemeralApplicationIcon"); @@ -7110,9 +7381,15 @@ public class PackageManagerService extends IPackageManager.Stub { int errorCode = PackageManager.INSTALL_SUCCEEDED; if (throwable == null) { + // Static shared libraries have synthetic package names + if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) { + renameStaticSharedLibraryPackage(parseResult.pkg); + } try { - scanPackageLI(parseResult.pkg, parseResult.scanFile, parseFlags, scanFlags, - currentTime, null); + if (errorCode == PackageManager.INSTALL_SUCCEEDED) { + scanPackageLI(parseResult.pkg, parseResult.scanFile, parseFlags, scanFlags, + currentTime, null); + } } catch (PackageManagerException e) { errorCode = e.error; Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage()); @@ -7266,6 +7543,11 @@ public class PackageManagerService extends IPackageManager.Stub { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } + // Static shared libraries have synthetic package names + if (pkg.applicationInfo.isStaticSharedLibrary()) { + renameStaticSharedLibraryPackage(pkg); + } + return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user); } @@ -7568,6 +7850,12 @@ public class PackageManagerService extends IPackageManager.Stub { return scannedPkg; } + private void renameStaticSharedLibraryPackage(PackageParser.Package pkg) { + // Derive the new package synthetic package name + pkg.setPackageName(pkg.packageName + STATIC_SHARED_LIB_DELIMITER + + pkg.staticSharedLibVersion); + } + private static String fixProcessName(String defProcessName, String processName) { if (processName == null) { @@ -7923,8 +8211,9 @@ public class PackageManagerService extends IPackageManager.Stub { targetCompilerFilter, getOrCreateCompilerPackageStats(p)); } - Collection<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package p) { - if (p.usesLibraries != null || p.usesOptionalLibraries != null) { + List<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package p) { + if (p.usesLibraries != null || p.usesOptionalLibraries != null + || p.usesStaticLibraries != null) { ArrayList<PackageParser.Package> retValue = new ArrayList<>(); Set<String> collectedNames = new HashSet<>(); findSharedNonSystemLibrariesRecursive(p, retValue, collectedNames); @@ -7938,37 +8227,74 @@ public class PackageManagerService extends IPackageManager.Stub { } private void findSharedNonSystemLibrariesRecursive(PackageParser.Package p, - Collection<PackageParser.Package> collected, Set<String> collectedNames) { + ArrayList<PackageParser.Package> collected, Set<String> collectedNames) { if (!collectedNames.contains(p.packageName)) { collectedNames.add(p.packageName); collected.add(p); if (p.usesLibraries != null) { - findSharedNonSystemLibrariesRecursive(p.usesLibraries, collected, collectedNames); + findSharedNonSystemLibrariesRecursive(p.usesLibraries, + null, collected, collectedNames); } if (p.usesOptionalLibraries != null) { - findSharedNonSystemLibrariesRecursive(p.usesOptionalLibraries, collected, - collectedNames); + findSharedNonSystemLibrariesRecursive(p.usesOptionalLibraries, + null, collected, collectedNames); + } + if (p.usesStaticLibraries != null) { + findSharedNonSystemLibrariesRecursive(p.usesStaticLibraries, + p.usesStaticLibrariesVersions, collected, collectedNames); } } } - private void findSharedNonSystemLibrariesRecursive(Collection<String> libs, - Collection<PackageParser.Package> collected, Set<String> collectedNames) { - for (String libName : libs) { - PackageParser.Package libPkg = findSharedNonSystemLibrary(libName); + private void findSharedNonSystemLibrariesRecursive(ArrayList<String> libs, int[] versions, + ArrayList<PackageParser.Package> collected, Set<String> collectedNames) { + final int libNameCount = libs.size(); + for (int i = 0; i < libNameCount; i++) { + String libName = libs.get(i); + int version = (versions != null && versions.length == libNameCount) + ? versions[i] : PackageManager.VERSION_CODE_HIGHEST; + PackageParser.Package libPkg = findSharedNonSystemLibrary(libName, version); if (libPkg != null) { findSharedNonSystemLibrariesRecursive(libPkg, collected, collectedNames); } } } - private PackageParser.Package findSharedNonSystemLibrary(String libName) { + private PackageParser.Package findSharedNonSystemLibrary(String name, int version) { synchronized (mPackages) { - PackageManagerService.SharedLibraryEntry lib = mSharedLibraries.get(libName); - if (lib != null && lib.apk != null) { - return mPackages.get(lib.apk); + SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(name, version); + if (libEntry != null) { + return mPackages.get(libEntry.apk); } + return null; + } + } + + private SharedLibraryEntry getSharedLibraryEntryLPr(String name, int version) { + SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name); + if (versionedLib == null) { + return null; + } + return versionedLib.get(version); + } + + private SharedLibraryEntry getLatestSharedLibraVersionLPr(PackageParser.Package pkg) { + SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get( + pkg.staticSharedLibName); + if (versionedLib == null) { + return null; + } + int previousLibVersion = -1; + final int versionCount = versionedLib.size(); + for (int i = 0; i < versionCount; i++) { + final int libVersion = versionedLib.keyAt(i); + if (libVersion < pkg.staticSharedLibVersion) { + previousLibVersion = Math.max(previousLibVersion, libVersion); + } + } + if (previousLibVersion >= 0) { + return versionedLib.get(previousLibVersion); } return null; } @@ -8262,36 +8588,84 @@ public class PackageManagerService extends IPackageManager.Stub { private void updateSharedLibrariesLPr(PackageParser.Package pkg, PackageParser.Package changingLib) throws PackageManagerException { - if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) { - final ArraySet<String> usesLibraryFiles = new ArraySet<>(); - int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0; - for (int i=0; i<N; i++) { - final SharedLibraryEntry file = mSharedLibraries.get(pkg.usesLibraries.get(i)); - if (file == null) { + if (pkg == null) { + return; + } + ArraySet<String> usesLibraryFiles = null; + if (pkg.usesLibraries != null) { + usesLibraryFiles = addSharedLibrariesLPw(pkg.usesLibraries, + null, null, pkg.packageName, changingLib, true, null); + } + if (pkg.usesStaticLibraries != null) { + usesLibraryFiles = addSharedLibrariesLPw(pkg.usesStaticLibraries, + pkg.usesStaticLibrariesVersions, pkg.usesStaticLibrariesCertDigests, + pkg.packageName, changingLib, true, usesLibraryFiles); + } + if (pkg.usesOptionalLibraries != null) { + usesLibraryFiles = addSharedLibrariesLPw(pkg.usesOptionalLibraries, + null, null, pkg.packageName, changingLib, false, usesLibraryFiles); + } + if (!ArrayUtils.isEmpty(usesLibraryFiles)) { + pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[usesLibraryFiles.size()]); + } else { + pkg.usesLibraryFiles = null; + } + } + + private ArraySet<String> addSharedLibrariesLPw(@NonNull List<String> requestedLibraries, + @Nullable int[] requiredVersions, @Nullable String[] requiredCertDigests, + @NonNull String packageName, @Nullable PackageParser.Package changingLib, + boolean required, @Nullable ArraySet<String> outUsedLibraries) + throws PackageManagerException { + final int libCount = requestedLibraries.size(); + for (int i = 0; i < libCount; i++) { + final String libName = requestedLibraries.get(i); + final int libVersion = requiredVersions != null ? requiredVersions[i] + : SharedLibraryInfo.VERSION_UNDEFINED; + final SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(libName, libVersion); + if (libEntry == null) { + if (required) { throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY, - "Package " + pkg.packageName + " requires unavailable shared library " - + pkg.usesLibraries.get(i) + "; failing!"); - } - addSharedLibraryLPr(usesLibraryFiles, file, changingLib); - } - N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0; - for (int i=0; i<N; i++) { - final SharedLibraryEntry file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i)); - if (file == null) { - Slog.w(TAG, "Package " + pkg.packageName - + " desires unavailable shared library " - + pkg.usesOptionalLibraries.get(i) + "; ignoring!"); + "Package " + packageName + " requires unavailable shared library " + + libName + "; failing!"); } else { - addSharedLibraryLPr(usesLibraryFiles, file, changingLib); + Slog.w(TAG, "Package " + packageName + + " desires unavailable shared library " + + libName + "; ignoring!"); } - } - N = usesLibraryFiles.size(); - if (N > 0) { - pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[N]); } else { - pkg.usesLibraryFiles = null; + if (requiredVersions != null && requiredCertDigests != null) { + if (libEntry.info.getVersion() != requiredVersions[i]) { + throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY, + "Package " + packageName + " requires unavailable static shared" + + " library " + libName + " version " + + libEntry.info.getVersion() + "; failing!"); + } + + PackageParser.Package libPkg = mPackages.get(libEntry.apk); + if (libPkg == null) { + throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY, + "Package " + packageName + " requires unavailable static shared" + + " library; failing!"); + } + + String expectedCertDigest = requiredCertDigests[i]; + String libCertDigest = PackageUtils.computeCertSha256Digest( + libPkg.mSignatures[0]); + if (!libCertDigest.equalsIgnoreCase(expectedCertDigest)) { + throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY, + "Package " + packageName + " requires differently signed" + + " static shared library; failing!"); + } + } + + if (outUsedLibraries == null) { + outUsedLibraries = new ArraySet<>(); + } + addSharedLibraryLPr(outUsedLibraries, libEntry, changingLib); } } + return outUsedLibraries; } private static boolean hasString(List<String> list, List<String> which) { @@ -8308,31 +8682,36 @@ public class PackageManagerService extends IPackageManager.Stub { return false; } - private void updateAllSharedLibrariesLPw() { - for (PackageParser.Package pkg : mPackages.values()) { - try { - updateSharedLibrariesLPr(pkg, null); - } catch (PackageManagerException e) { - Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage()); - } - } - } - private ArrayList<PackageParser.Package> updateAllSharedLibrariesLPw( PackageParser.Package changingPkg) { ArrayList<PackageParser.Package> res = null; for (PackageParser.Package pkg : mPackages.values()) { - if (hasString(pkg.usesLibraries, changingPkg.libraryNames) - || hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)) { - if (res == null) { - res = new ArrayList<PackageParser.Package>(); - } - res.add(pkg); - try { - updateSharedLibrariesLPr(pkg, changingPkg); - } catch (PackageManagerException e) { - Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage()); + if (changingPkg != null + && !hasString(pkg.usesLibraries, changingPkg.libraryNames) + && !hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames) + && !ArrayUtils.contains(pkg.usesStaticLibraries, + changingPkg.staticSharedLibName)) { + return null; + } + if (res == null) { + res = new ArrayList<>(); + } + res.add(pkg); + try { + updateSharedLibrariesLPr(pkg, changingPkg); + } catch (PackageManagerException e) { + // If a system app update or an app and a required lib missing we + // delete the package and for updated system apps keep the data as + // it is better for the user to reinstall than to be in an limbo + // state. Also libs disappearing under an app should never happen + // - just in case. + if (!pkg.isSystemApp() || pkg.isUpdatedSystemApp()) { + final int flags = pkg.isUpdatedSystemApp() + ? PackageManager.DELETE_KEEP_DATA : 0; + deletePackageLIF(pkg.packageName, null, true, sUserManager.getUserIds(), + flags , null, true, null); } + Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage()); } } return res; @@ -8590,9 +8969,17 @@ public class PackageManagerService extends IPackageManager.Stub { pkgSetting == null ? null : new PackageSetting(pkgSetting); final PackageSetting disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(pkg.packageName); + + String[] usesStaticLibraries = null; + if (pkg.usesStaticLibraries != null) { + usesStaticLibraries = new String[pkg.usesStaticLibraries.size()]; + pkg.usesStaticLibraries.toArray(usesStaticLibraries); + } + if (pkgSetting == null) { final String parentPackageName = (pkg.parentPackage != null) ? pkg.parentPackage.packageName : null; + // REMOVE SharedUserSetting from method; update in a separate call pkgSetting = Settings.createNewSetting(pkg.packageName, origPackage, disabledPkgSetting, realName, suid, destCodeFile, destResourceFile, @@ -8600,7 +8987,8 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.secondaryCpuAbi, pkg.mVersionCode, pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags, user, true /*allowInstall*/, parentPackageName, pkg.getChildPackageNames(), - UserManagerService.getInstance()); + UserManagerService.getInstance(), usesStaticLibraries, + pkg.usesStaticLibrariesVersions); // SIDE EFFECTS; updates system state; move elsewhere if (origPackage != null) { mSettings.addRenamedPackageLPw(pkg.packageName, origPackage.name); @@ -8616,7 +9004,8 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.nativeLibraryDir, pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi, pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags, pkg.getChildPackageNames(), - UserManagerService.getInstance()); + UserManagerService.getInstance(), usesStaticLibraries, + pkg.usesStaticLibrariesVersions); } // SIDE EFFECTS; persists system state to files on disk; move elsewhere mSettings.writeUserRestrictionsLPw(pkgSetting, oldPkgSetting); @@ -8653,12 +9042,15 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; } - if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { + if ((scanFlags & SCAN_BOOTING) == 0 + && (policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { // Check all shared libraries and map to their actual file path. // We only do this here for apps not on a system dir, because those // are the only ones that can fail an install due to this. We // will take care of the system apps by updating all of their - // library paths after the scan is done. + // library paths after the scan is done. Also during the initial + // scan don't update any libs as we do this wholesale after all + // apps are scanned to avoid dependency based scanning. updateSharedLibrariesLPr(pkg, null); } @@ -8668,8 +9060,22 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.uid = pkgSetting.appId; pkg.mExtras = pkgSetting; - if (shouldCheckUpgradeKeySetLP(pkgSetting, scanFlags)) { - if (checkUpgradeKeySetLP(pkgSetting, pkg)) { + + + // Static shared libs have same package with different versions where + // we internally use a synthetic package name to allow multiple versions + // of the same package, therefore we need to compare signatures against + // the package setting for the latest library version. + PackageSetting signatureCheckPs = pkgSetting; + if (pkg.applicationInfo.isStaticSharedLibrary()) { + SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg); + if (libraryEntry != null) { + signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk); + } + } + + if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) { + if (checkUpgradeKeySetLP(signatureCheckPs, pkg)) { // We just determined the app is signed correctly, so bring // over the latest parsed certs. pkgSetting.signatures.mSignatures = pkg.mSignatures; @@ -8688,7 +9094,7 @@ public class PackageManagerService extends IPackageManager.Stub { } else { try { // SIDE EFFECTS; compareSignaturesCompat() changes KeysetManagerService - verifySignaturesLP(pkgSetting, pkg); + verifySignaturesLP(signatureCheckPs, pkg); // We just determined the app is signed correctly, so bring // over the latest parsed certs. pkgSetting.signatures.mSignatures = pkg.mSignatures; @@ -8704,8 +9110,8 @@ public class PackageManagerService extends IPackageManager.Stub { // What this means is that you can't change the signatures // associated with an overall shared user, which doesn't seem all // that unreasonable. - if (pkgSetting.sharedUser != null) { - if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures, + if (signatureCheckPs.sharedUser != null) { + if (compareSignatures(signatureCheckPs.sharedUser.signatures.mSignatures, pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) { throw new PackageManagerException( INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, @@ -8946,7 +9352,7 @@ public class PackageManagerService extends IPackageManager.Stub { } /** - * Asserts the parsed package is valid according to teh given policy. If the + * Asserts the parsed package is valid according to the given policy. If the * package is invalid, for whatever reason, throws {@link PackgeManagerException}. * <p> * Implementation detail: This method must NOT have any side effects. It would @@ -8992,6 +9398,128 @@ public class PackageManagerService extends IPackageManager.Stub { + " already installed. Skipping duplicate."); } + if (pkg.applicationInfo.isStaticSharedLibrary()) { + // Static libs have a synthetic package name containing the version + // but we still want the base name to be unique. + if (mPackages.containsKey(pkg.manifestPackageName)) { + throw new PackageManagerException( + "Duplicate static shared lib provider package"); + } + + // Static shared libraries should have at least O target SDK + if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) { + throw new PackageManagerException( + "Packages declaring static-shared libs must target O SDK or higher"); + } + + // Package declaring static a shared lib cannot be ephemeral + if (pkg.applicationInfo.isEphemeralApp()) { + throw new PackageManagerException( + "Packages declaring static-shared libs cannot be ephemeral"); + } + + // Package declaring static a shared lib cannot be renamed since the package + // name is synthetic and apps can't code around package manager internals. + if (!ArrayUtils.isEmpty(pkg.mOriginalPackages)) { + throw new PackageManagerException( + "Packages declaring static-shared libs cannot be renamed"); + } + + // Package declaring static a shared lib cannot declare child packages + if (!ArrayUtils.isEmpty(pkg.childPackages)) { + throw new PackageManagerException( + "Packages declaring static-shared libs cannot have child packages"); + } + + // Package declaring static a shared lib cannot declare dynamic libs + if (!ArrayUtils.isEmpty(pkg.libraryNames)) { + throw new PackageManagerException( + "Packages declaring static-shared libs cannot declare dynamic libs"); + } + + // Package declaring static a shared lib cannot declare shared users + if (pkg.mSharedUserId != null) { + throw new PackageManagerException( + "Packages declaring static-shared libs cannot declare shared users"); + } + + // Static shared libs cannot declare activities + if (!pkg.activities.isEmpty()) { + throw new PackageManagerException( + "Static shared libs cannot declare activities"); + } + + // Static shared libs cannot declare services + if (!pkg.services.isEmpty()) { + throw new PackageManagerException( + "Static shared libs cannot declare services"); + } + + // Static shared libs cannot declare providers + if (!pkg.providers.isEmpty()) { + throw new PackageManagerException( + "Static shared libs cannot declare content providers"); + } + + // Static shared libs cannot declare receivers + if (!pkg.receivers.isEmpty()) { + throw new PackageManagerException( + "Static shared libs cannot declare broadcast receivers"); + } + + // Static shared libs cannot declare permission groups + if (!pkg.permissionGroups.isEmpty()) { + throw new PackageManagerException( + "Static shared libs cannot declare permission groups"); + } + + // Static shared libs cannot declare permissions + if (!pkg.permissions.isEmpty()) { + throw new PackageManagerException( + "Static shared libs cannot declare permissions"); + } + + // Static shared libs cannot declare protected broadcasts + if (pkg.protectedBroadcasts != null) { + throw new PackageManagerException( + "Static shared libs cannot declare protected broadcasts"); + } + + // Static shared libs cannot be overlay targets + if (pkg.mOverlayTarget != null) { + throw new PackageManagerException( + "Static shared libs cannot be overlay targets"); + } + + // The version codes must be ordered as lib versions + int minVersionCode = Integer.MIN_VALUE; + int maxVersionCode = Integer.MAX_VALUE; + + SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get( + pkg.staticSharedLibName); + if (versionedLib != null) { + final int versionCount = versionedLib.size(); + for (int i = 0; i < versionCount; i++) { + SharedLibraryInfo libInfo = versionedLib.valueAt(i).info; + // TODO: We will change version code to long, so in the new API it is long + final int libVersionCode = (int) libInfo.getDeclaringPackage() + .getVersionCode(); + if (libInfo.getVersion() < pkg.staticSharedLibVersion) { + minVersionCode = Math.max(minVersionCode, libVersionCode + 1); + } else if (libInfo.getVersion() > pkg.staticSharedLibVersion) { + maxVersionCode = Math.min(maxVersionCode, libVersionCode - 1); + } else { + minVersionCode = maxVersionCode = libVersionCode; + break; + } + } + } + if (pkg.mVersionCode < minVersionCode || pkg.mVersionCode > maxVersionCode) { + throw new PackageManagerException("Static shared" + + " lib version codes must be ordered as lib versions"); + } + } + // Only privileged apps and updated privileged apps can add child packages. if (pkg.childPackages != null && !pkg.childPackages.isEmpty()) { if ((policyFlags & PARSE_IS_PRIVILEGED) == 0) { @@ -9072,6 +9600,45 @@ public class PackageManagerService extends IPackageManager.Stub { } } + private boolean addSharedLibraryLPw(String path, String apk, String name, int version, + int type, String declaringPackageName, int declaringVersionCode) { + SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name); + if (versionedLib == null) { + versionedLib = new SparseArray<>(); + mSharedLibraries.put(name, versionedLib); + if (type == SharedLibraryInfo.TYPE_STATIC) { + mStaticLibsByDeclaringPackage.put(declaringPackageName, versionedLib); + } + } else if (versionedLib.indexOfKey(version) >= 0) { + return false; + } + SharedLibraryEntry libEntry = new SharedLibraryEntry(path, apk, name, + version, type, declaringPackageName, declaringVersionCode); + versionedLib.put(version, libEntry); + return true; + } + + private boolean removeSharedLibraryLPw(String name, int version) { + SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name); + if (versionedLib == null) { + return false; + } + final int libIdx = versionedLib.indexOfKey(version); + if (libIdx < 0) { + return false; + } + SharedLibraryEntry libEntry = versionedLib.valueAt(libIdx); + versionedLib.remove(version); + if (versionedLib.size() <= 0) { + mSharedLibraries.remove(name); + if (libEntry.info.getType() == SharedLibraryInfo.TYPE_STATIC) { + mStaticLibsByDeclaringPackage.remove(libEntry.info.getDeclaringPackage() + .getPackageName()); + } + } + return true; + } + /** * Adds a scanned package to the system. When this method is finished, the package will * be available for query, resolution, etc... @@ -9124,10 +9691,30 @@ public class PackageManagerService extends IPackageManager.Stub { ArrayList<PackageParser.Package> clientLibPkgs = null; // writer synchronized (mPackages) { - if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { - // Only system apps can add new shared libraries. + boolean hasStaticSharedLibs = false; + + // Any app can add new static shared libraries + if (pkg.staticSharedLibName != null) { + // Static shared libs don't allow renaming as they have synthetic package + // names to allow install of multiple versions, so use name from manifest. + if (addSharedLibraryLPw(null, pkg.packageName, pkg.staticSharedLibName, + pkg.staticSharedLibVersion, SharedLibraryInfo.TYPE_STATIC, + pkg.manifestPackageName, pkg.mVersionCode)) { + hasStaticSharedLibs = true; + } else { + Slog.w(TAG, "Package " + pkg.packageName + " library " + + pkg.staticSharedLibName + " already exists; skipping"); + } + // Static shared libs cannot be updated once installed since they + // use synthetic package name which includes the version code, so + // not need to update other packages's shared lib dependencies. + } + + if (!hasStaticSharedLibs + && (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + // Only system apps can add new dynamic shared libraries. if (pkg.libraryNames != null) { - for (int i=0; i<pkg.libraryNames.size(); i++) { + for (int i = 0; i < pkg.libraryNames.size(); i++) { String name = pkg.libraryNames.get(i); boolean allowed = false; if (pkg.isUpdatedSystemApp()) { @@ -9144,7 +9731,7 @@ public class PackageManagerService extends IPackageManager.Stub { final PackageSetting sysPs = mSettings .getDisabledSystemPkgLPr(pkg.packageName); if (sysPs.pkg != null && sysPs.pkg.libraryNames != null) { - for (int j=0; j<sysPs.pkg.libraryNames.size(); j++) { + for (int j = 0; j < sysPs.pkg.libraryNames.size(); j++) { if (name.equals(sysPs.pkg.libraryNames.get(j))) { allowed = true; break; @@ -9155,9 +9742,10 @@ public class PackageManagerService extends IPackageManager.Stub { allowed = true; } if (allowed) { - if (!mSharedLibraries.containsKey(name)) { - mSharedLibraries.put(name, new SharedLibraryEntry(null, pkg.packageName)); - } else if (!name.equals(pkg.packageName)) { + if (!addSharedLibraryLPw(null, pkg.packageName, name, + SharedLibraryInfo.VERSION_UNDEFINED, + SharedLibraryInfo.TYPE_DYNAMIC, + pkg.packageName, pkg.mVersionCode)) { Slog.w(TAG, "Package " + pkg.packageName + " library " + name + " already exists; skipping"); } @@ -9166,6 +9754,7 @@ public class PackageManagerService extends IPackageManager.Stub { + name + " that is not declared on system image; skipping"); } } + if ((scanFlags & SCAN_BOOTING) == 0) { // If we are not booting, we need to update any applications // that are clients of our shared library. If we are booting, @@ -10379,11 +10968,9 @@ public class PackageManagerService extends IPackageManager.Stub { if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { // Only system apps can hold shared libraries. if (pkg.libraryNames != null) { - for (i=0; i<pkg.libraryNames.size(); i++) { + for (i = 0; i < pkg.libraryNames.size(); i++) { String name = pkg.libraryNames.get(i); - SharedLibraryEntry cur = mSharedLibraries.get(name); - if (cur != null && cur.apk != null && cur.apk.equals(pkg.packageName)) { - mSharedLibraries.remove(name); + if (removeSharedLibraryLPw(name, 0)) { if (DEBUG_REMOVE && chatty) { if (r == null) { r = new StringBuilder(256); @@ -10396,6 +10983,23 @@ public class PackageManagerService extends IPackageManager.Stub { } } } + + r = null; + + // Any package can hold static shared libraries. + if (pkg.staticSharedLibName != null) { + if (removeSharedLibraryLPw(pkg.staticSharedLibName, pkg.staticSharedLibVersion)) { + if (DEBUG_REMOVE && chatty) { + if (r == null) { + r = new StringBuilder(256); + } else { + r.append(' '); + } + r.append(pkg.staticSharedLibName); + } + } + } + if (r != null) { if (DEBUG_REMOVE) Log.d(TAG, " Libraries: " + r); } @@ -12457,6 +13061,16 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.w(TAG, "Cannot hide package: android"); return false; } + // Cannot hide static shared libs as they are considered + // a part of the using app (emulating static linking). Also + // static libs are installed always on internal storage. + PackageParser.Package pkg = mPackages.get(packageName); + if (pkg != null && pkg.staticSharedLibName != null) { + Slog.w(TAG, "Cannot hide package: " + packageName + + " providing static shared library: " + + pkg.staticSharedLibName); + return false; + } // Only allow protected packages to hide themselves. if (hidden && !UserHandle.isSameApp(uid, pkgSetting.appId) && mProtectedPackages.isPackageStateProtected(userId, packageName)) { @@ -12717,6 +13331,17 @@ public class PackageManagerService extends IPackageManager.Stub { return false; } + // Cannot suspend static shared libs as they are considered + // a part of the using app (emulating static linking). Also + // static libs are installed always on internal storage. + PackageParser.Package pkg = mPackages.get(packageName); + if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) { + Slog.w(TAG, "Cannot suspend package: " + packageName + + " providing static shared library: " + + pkg.staticSharedLibName); + return false; + } + return true; } @@ -15150,6 +15775,7 @@ public class PackageManagerService extends IPackageManager.Stub { res.removedInfo = new PackageRemovedInfo(); res.removedInfo.uid = oldPackage.applicationInfo.uid; res.removedInfo.removedPackage = oldPackage.packageName; + res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null; res.removedInfo.isUpdate = true; res.removedInfo.origUsers = installedUsers; final PackageSetting ps = mSettings.getPackageLPr(pkgName); @@ -15812,6 +16438,19 @@ public class PackageManagerService extends IPackageManager.Stub { return; } + if (pkg.applicationInfo.isStaticSharedLibrary()) { + // Static shared libraries have synthetic package names + renameStaticSharedLibraryPackage(pkg); + + // No static shared libs on external storage + if (onExternal) { + Slog.i(TAG, "Static shared libs can only be installed on internal storage."); + res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION, + "Packages declaring static-shared libs cannot be updated"); + return; + } + } + // If we are installing a clustered package add results for the children if (pkg.childPackages != null) { synchronized (mPackages) { @@ -15936,11 +16575,23 @@ public class PackageManagerService extends IPackageManager.Stub { if (ps != null) { if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps); + // Static shared libs have same package with different versions where + // we internally use a synthetic package name to allow multiple versions + // of the same package, therefore we need to compare signatures against + // the package setting for the latest library version. + PackageSetting signatureCheckPs = ps; + if (pkg.applicationInfo.isStaticSharedLibrary()) { + SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg); + if (libraryEntry != null) { + signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk); + } + } + // Quick sanity check that we're signed correctly if updating; // we'll check this again later when scanning, but we want to // bail early here before tripping over redefined permissions. - if (shouldCheckUpgradeKeySetLP(ps, scanFlags)) { - if (!checkUpgradeKeySetLP(ps, pkg)) { + if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) { + if (!checkUpgradeKeySetLP(signatureCheckPs, pkg)) { res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " + pkg.packageName + " upgrade keys do not match the " + "previously installed version"); @@ -15948,7 +16599,7 @@ public class PackageManagerService extends IPackageManager.Stub { } } else { try { - verifySignaturesLP(ps, pkg); + verifySignaturesLP(signatureCheckPs, pkg); } catch (PackageManagerException e) { res.setError(e.error, e.getMessage()); return; @@ -16065,14 +16716,6 @@ public class PackageManagerService extends IPackageManager.Stub { return; } - // Shared libraries for the package need to be updated. - synchronized (mPackages) { - try { - updateSharedLibrariesLPr(pkg, null); - } catch (PackageManagerException e) { - Slog.e(TAG, "updateSharedLibrariesLPw failed: " + e.getMessage()); - } - } Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); // Do not run PackageDexOptimizer through the local performDexOpt // method because `pkg` may not be in `mPackages` yet. @@ -16100,6 +16743,18 @@ public class PackageManagerService extends IPackageManager.Stub { try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags, "installPackageLI")) { if (replace) { + if (pkg.applicationInfo.isStaticSharedLibrary()) { + // Static libs have a synthetic package name containing the version + // and cannot be updated as an update would get a new package name, + // unless this is the exact same version code which is useful for + // development. + PackageParser.Package existingPkg = mPackages.get(pkg.packageName); + if (existingPkg != null && existingPkg.mVersionCode != pkg.mVersionCode) { + res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring " + + "static-shared libs cannot be updated"); + return; + } + } replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user, installerPackageName, res, args.installReason); } else { @@ -16345,22 +17000,37 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override - public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int userId, - int flags) { - deletePackage(packageName, new LegacyPackageDeleteObserver(observer).getBinder(), userId, - flags); + public void deletePackageAsUser(String packageName, int versionCode, + IPackageDeleteObserver observer, int userId, int flags) { + deletePackageVersioned(new VersionedPackage(packageName, versionCode), + new LegacyPackageDeleteObserver(observer).getBinder(), userId, flags); } @Override - public void deletePackage(final String packageName, + public void deletePackageVersioned(VersionedPackage versionedPackage, final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.DELETE_PACKAGES, null); - Preconditions.checkNotNull(packageName); + Preconditions.checkNotNull(versionedPackage); Preconditions.checkNotNull(observer); + Preconditions.checkArgumentInRange(versionedPackage.getVersionCode(), + PackageManager.VERSION_CODE_HIGHEST, + Integer.MAX_VALUE, "versionCode must be >= -1"); + + final String packageName = versionedPackage.getPackageName(); + // TODO: We will change version code to long, so in the new API it is long + final int versionCode = (int) versionedPackage.getVersionCode(); + final String internalPackageName; + synchronized (mPackages) { + // Normalize package name to handle renamed packages and static libs + internalPackageName = resolveInternalPackageNameLPr(versionedPackage.getPackageName(), + // TODO: We will change version code to long, so in the new API it is long + (int) versionedPackage.getVersionCode()); + } + final int uid = Binder.getCallingUid(); - if (!isOrphaned(packageName) - && !isCallerAllowedToSilentlyUninstall(uid, packageName)) { + if (!isOrphaned(internalPackageName) + && !isCallerAllowedToSilentlyUninstall(uid, internalPackageName)) { try { final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null)); @@ -16387,7 +17057,7 @@ public class PackageManagerService extends IPackageManager.Stub { return; } - if (!deleteAllUsers && getBlockUninstallForUser(packageName, userId)) { + if (!deleteAllUsers && getBlockUninstallForUser(internalPackageName, userId)) { try { observer.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_OWNER_BLOCKED, null); @@ -16397,8 +17067,10 @@ public class PackageManagerService extends IPackageManager.Stub { } if (DEBUG_REMOVE) { - Slog.d(TAG, "deletePackageAsUser: pkg=" + packageName + " user=" + userId - + " deleteAllUsers: " + deleteAllUsers ); + Slog.d(TAG, "deletePackageAsUser: pkg=" + internalPackageName + " user=" + userId + + " deleteAllUsers: " + deleteAllUsers + " version=" + + (versionCode == PackageManager.VERSION_CODE_HIGHEST + ? "VERSION_CODE_HIGHEST" : versionCode)); } // Queue up an async operation since the package deletion may take a little while. mHandler.post(new Runnable() { @@ -16406,18 +17078,22 @@ public class PackageManagerService extends IPackageManager.Stub { mHandler.removeCallbacks(this); int returnCode; if (!deleteAllUsers) { - returnCode = deletePackageX(packageName, userId, deleteFlags); + returnCode = deletePackageX(internalPackageName, versionCode, + userId, deleteFlags); } else { - int[] blockUninstallUserIds = getBlockUninstallForUsers(packageName, users); + int[] blockUninstallUserIds = getBlockUninstallForUsers( + internalPackageName, users); // If nobody is blocking uninstall, proceed with delete for all users if (ArrayUtils.isEmpty(blockUninstallUserIds)) { - returnCode = deletePackageX(packageName, userId, deleteFlags); + returnCode = deletePackageX(internalPackageName, versionCode, + userId, deleteFlags); } else { // Otherwise uninstall individually for users with blockUninstalls=false final int userFlags = deleteFlags & ~PackageManager.DELETE_ALL_USERS; for (int userId : users) { if (!ArrayUtils.contains(blockUninstallUserIds, userId)) { - returnCode = deletePackageX(packageName, userId, userFlags); + returnCode = deletePackageX(internalPackageName, versionCode, + userId, userFlags); if (returnCode != PackageManager.DELETE_SUCCEEDED) { Slog.w(TAG, "Package delete failed for user " + userId + ", returnCode " + returnCode); @@ -16438,6 +17114,80 @@ public class PackageManagerService extends IPackageManager.Stub { }); } + private String resolveExternalPackageNameLPr(PackageParser.Package pkg) { + if (pkg.staticSharedLibName != null) { + return pkg.manifestPackageName; + } + return pkg.packageName; + } + + private String resolveInternalPackageNameLPr(String packageName, int versionCode) { + // Handle renamed packages + String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName); + packageName = normalizedPackageName != null ? normalizedPackageName : packageName; + + // Is this a static library? + SparseArray<SharedLibraryEntry> versionedLib = + mStaticLibsByDeclaringPackage.get(packageName); + if (versionedLib == null || versionedLib.size() <= 0) { + return packageName; + } + + // Figure out which lib versions the caller can see + SparseIntArray versionsCallerCanSee = null; + final int callingAppId = UserHandle.getAppId(Binder.getCallingUid()); + if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.SHELL_UID + && callingAppId != Process.ROOT_UID) { + versionsCallerCanSee = new SparseIntArray(); + String libName = versionedLib.valueAt(0).info.getName(); + String[] uidPackages = getPackagesForUid(Binder.getCallingUid()); + if (uidPackages != null) { + for (String uidPackage : uidPackages) { + PackageSetting ps = mSettings.getPackageLPr(uidPackage); + final int libIdx = ArrayUtils.indexOf(ps.usesStaticLibraries, libName); + if (libIdx >= 0) { + final int libVersion = ps.usesStaticLibrariesVersions[libIdx]; + versionsCallerCanSee.append(libVersion, libVersion); + } + } + } + } + + // Caller can see nothing - done + if (versionsCallerCanSee != null && versionsCallerCanSee.size() <= 0) { + return packageName; + } + + // Find the version the caller can see and the app version code + SharedLibraryEntry highestVersion = null; + final int versionCount = versionedLib.size(); + for (int i = 0; i < versionCount; i++) { + SharedLibraryEntry libEntry = versionedLib.valueAt(i); + if (versionsCallerCanSee != null && versionsCallerCanSee.indexOfKey( + libEntry.info.getVersion()) < 0) { + continue; + } + // TODO: We will change version code to long, so in the new API it is long + final int libVersionCode = (int) libEntry.info.getDeclaringPackage().getVersionCode(); + if (versionCode != PackageManager.VERSION_CODE_HIGHEST) { + if (libVersionCode == versionCode) { + return libEntry.apk; + } + } else if (highestVersion == null) { + highestVersion = libEntry; + } else if (libVersionCode > highestVersion.info + .getDeclaringPackage().getVersionCode()) { + highestVersion = libEntry; + } + } + + if (highestVersion != null) { + return highestVersion.apk; + } + + return packageName; + } + private boolean isCallerAllowedToSilentlyUninstall(int callingUid, String pkgName) { if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID || callingUid == Process.SYSTEM_UID) { @@ -16536,7 +17286,7 @@ public class PackageManagerService extends IPackageManager.Stub { * persisting settings for later use * sending a broadcast if necessary */ - private int deletePackageX(String packageName, int userId, int deleteFlags) { + private int deletePackageX(String packageName, int versionCode, int userId, int deleteFlags) { final PackageRemovedInfo info = new PackageRemovedInfo(); final boolean res; @@ -16559,6 +17309,32 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.w(TAG, "Not removing non-existent package " + packageName); return PackageManager.DELETE_FAILED_INTERNAL_ERROR; } + + if (versionCode != PackageManager.VERSION_CODE_HIGHEST + && uninstalledPs.versionCode != versionCode) { + Slog.w(TAG, "Not removing package " + packageName + " with versionCode " + + uninstalledPs.versionCode + " != " + versionCode); + return PackageManager.DELETE_FAILED_INTERNAL_ERROR; + } + + // Static shared libs can be declared by any package, so let us not + // allow removing a package if it provides a lib others depend on. + PackageParser.Package pkg = mPackages.get(packageName); + if (pkg != null && pkg.staticSharedLibName != null) { + SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(pkg.staticSharedLibName, + pkg.staticSharedLibVersion); + if (libEntry != null) { + List<VersionedPackage> libClientPackages = getPackagesUsingSharedLibraryLPr( + libEntry.info, 0, userId); + if (!ArrayUtils.isEmpty(libClientPackages)) { + Slog.w(TAG, "Not removing package " + pkg.manifestPackageName + + " hosting lib " + libEntry.info.getName() + " version " + + libEntry.info.getVersion() + " used by " + libClientPackages); + return PackageManager.DELETE_FAILED_USED_SHARED_LIBRARY; + } + } + } + allUsers = sUserManager.getUserIds(); info.origUsers = uninstalledPs.queryInstalledUsers(allUsers, true); } @@ -16617,6 +17393,7 @@ public class PackageManagerService extends IPackageManager.Stub { boolean isUpdate; boolean dataRemoved; boolean removedForAllUsers; + boolean isStaticSharedLib; // Clean up resources deleted packages. InstallArgs args = null; ArrayMap<String, PackageRemovedInfo> removedChildPackages; @@ -16668,6 +17445,12 @@ public class PackageManagerService extends IPackageManager.Stub { } private void sendPackageRemovedBroadcastInternal(boolean killApp) { + // Don't send static shared library removal broadcasts as these + // libs are visible only the the apps that depend on them an one + // cannot remove the library if it has a dependency. + if (isStaticSharedLib) { + return; + } Bundle extras = new Bundle(2); extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid); extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved); @@ -16711,6 +17494,8 @@ public class PackageManagerService extends IPackageManager.Stub { deletedPs = mSettings.mPackages.get(packageName); if (outInfo != null) { outInfo.removedPackage = packageName; + outInfo.isStaticSharedLib = deletedPkg != null + && deletedPkg.staticSharedLibName != null; outInfo.removedUsers = deletedPs != null ? deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true) : null; @@ -16738,15 +17523,18 @@ public class PackageManagerService extends IPackageManager.Stub { schedulePackageCleaning(packageName, UserHandle.USER_ALL, true); } + int removedAppId = -1; + // writer synchronized (mPackages) { if (deletedPs != null) { if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) { clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL); clearDefaultBrowserIfNeeded(packageName); + mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName); + removedAppId = mSettings.removePackageLPw(packageName); if (outInfo != null) { - mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName); - outInfo.removedAppId = mSettings.removePackageLPw(packageName); + outInfo.removedAppId = removedAppId; } updatePermissionsLPw(deletedPs.name, null, 0); if (deletedPs.sharedUser != null) { @@ -16796,10 +17584,10 @@ public class PackageManagerService extends IPackageManager.Stub { mSettings.writeLPr(); } } - if (outInfo != null) { + if (removedAppId != -1) { // A user ID was deleted here. Go through all users and remove it // from KeyStore. - removeKeystoreDataIfNeeded(UserHandle.USER_ALL, outInfo.removedAppId); + removeKeystoreDataIfNeeded(UserHandle.USER_ALL, removedAppId); } } @@ -16915,12 +17703,6 @@ public class PackageManagerService extends IPackageManager.Stub { + e.getMessage()); return false; } - try { - // update shared libraries for the newly re-installed system package - updateSharedLibrariesLPr(newPkg, null); - } catch (PackageManagerException e) { - Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage()); - } prepareAppDataAfterInstallLIF(newPkg); @@ -17033,6 +17815,15 @@ public class PackageManagerService extends IPackageManager.Stub { Log.i(TAG, "Package doesn't exist in set block uninstall " + packageName); return false; } + // Cannot block uninstall of static shared libs as they are + // considered a part of the using app (emulating static linking). + // Also static libs are installed always on internal storage. + PackageParser.Package pkg = mPackages.get(packageName); + if (pkg != null && pkg.staticSharedLibName != null) { + Slog.w(TAG, "Cannot block uninstall of package: " + packageName + + " providing static shared library: " + pkg.staticSharedLibName); + return false; + } if (!ps.getInstalled(userId)) { // Can't block uninstall for an app that is not installed or enabled. Log.i(TAG, "Package not installed in set block uninstall " + packageName); @@ -17094,7 +17885,6 @@ public class PackageManagerService extends IPackageManager.Stub { if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user); PackageSetting ps; - synchronized (mPackages) { ps = mSettings.mPackages.get(packageName); if (ps == null) { @@ -17287,6 +18077,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (outInfo != null) { outInfo.removedPackage = ps.name; + outInfo.isStaticSharedLib = pkg != null && pkg.staticSharedLibName != null; outInfo.removedAppId = ps.appId; outInfo.removedUsers = userIds; } @@ -19307,6 +20098,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); pw.println("Error: check-permission missing package argument"); return; } + String pkg = args[opti]; opti++; int user = UserHandle.getUserId(Binder.getCallingUid()); @@ -19319,6 +20111,10 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); return; } } + + // Normalize package name to handle renamed packages and static libs + pkg = resolveInternalPackageNameLPr(pkg, PackageManager.VERSION_CODE_HIGHEST); + pw.println(checkPermission(perm, pkg, user)); return; } else if ("l".equals(cmd) || "libraries".equals(cmd)) { @@ -19471,41 +20267,41 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); boolean printedHeader = false; final Iterator<String> it = mSharedLibraries.keySet().iterator(); while (it.hasNext()) { - String name = it.next(); - SharedLibraryEntry ent = mSharedLibraries.get(name); - if (!checkin) { - if (!printedHeader) { - if (dumpState.onTitlePrinted()) - pw.println(); - pw.println("Libraries:"); - printedHeader = true; - } - pw.print(" "); - } else { - pw.print("lib,"); - } - pw.print(name); - if (!checkin) { - pw.print(" -> "); + String libName = it.next(); + SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(libName); + if (versionedLib == null) { + continue; } - if (ent.path != null) { + final int versionCount = versionedLib.size(); + for (int i = 0; i < versionCount; i++) { + SharedLibraryEntry libEntry = versionedLib.valueAt(i); if (!checkin) { - pw.print("(jar) "); - pw.print(ent.path); + if (!printedHeader) { + if (dumpState.onTitlePrinted()) + pw.println(); + pw.println("Libraries:"); + printedHeader = true; + } + pw.print(" "); } else { - pw.print(",jar,"); - pw.print(ent.path); + pw.print("lib,"); + } + pw.print(libEntry.info.getName()); + if (libEntry.info.isStatic()) { + pw.print(" version=" + libEntry.info.getVersion()); } - } else { if (!checkin) { - pw.print("(apk) "); - pw.print(ent.apk); + pw.print(" -> "); + } + if (libEntry.path != null) { + pw.print(" (jar) "); + pw.print(libEntry.path); } else { - pw.print(",apk,"); - pw.print(ent.apk); + pw.print(" (apk) "); + pw.print(libEntry.apk); } + pw.println(); } - pw.println(); } } @@ -20619,14 +21415,29 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } } + private List<String> collectAbsoluteCodePaths() { + synchronized (mPackages) { + List<String> codePaths = new ArrayList<>(); + final int packageCount = mSettings.mPackages.size(); + for (int i = 0; i < packageCount; i++) { + final PackageSetting ps = mSettings.mPackages.valueAt(i); + codePaths.add(ps.codePath.getAbsolutePath()); + } + return codePaths; + } + } + /** * Examine all apps present on given mounted volume, and destroy apps that * aren't expected, either due to uninstallation or reinstallation on * another volume. */ private void reconcileApps(String volumeUuid) { - final File[] files = FileUtils - .listFilesOrEmpty(Environment.getDataAppDirectory(volumeUuid)); + List<String> absoluteCodePaths = collectAbsoluteCodePaths(); + List<File> filesToDelete = null; + + final File[] files = FileUtils.listFilesOrEmpty( + Environment.getDataAppDirectory(volumeUuid)); for (File file : files) { final boolean isPackage = (isApkFile(file) || file.isDirectory()) && !PackageInstallerService.isStageName(file.getName()); @@ -20635,15 +21446,33 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); continue; } - try { - final PackageLite pkg = PackageParser.parsePackageLite(file, - PackageParser.PARSE_MUST_BE_APK); - assertPackageKnown(volumeUuid, pkg.packageName); + String absolutePath = file.getAbsolutePath(); + + boolean pathValid = false; + final int absoluteCodePathCount = absoluteCodePaths.size(); + for (int i = 0; i < absoluteCodePathCount; i++) { + String absoluteCodePath = absoluteCodePaths.get(i); + if (absolutePath.startsWith(absoluteCodePath)) { + pathValid = true; + break; + } + } + + if (!pathValid) { + if (filesToDelete == null) { + filesToDelete = new ArrayList<>(); + } + filesToDelete.add(file); + } + } - } catch (PackageParserException | PackageManagerException e) { - logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e); + if (filesToDelete != null) { + final int fileToDeleteCount = filesToDelete.size(); + for (int i = 0; i < fileToDeleteCount; i++) { + File fileToDelete = filesToDelete.get(i); + logCriticalInfo(Log.WARN, "Destroying orphaned" + fileToDelete); synchronized (mInstallLock) { - removeCodePathLI(file); + removeCodePathLI(fileToDelete); } } } @@ -21421,7 +22250,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } mHandler.post(new Runnable() { public void run() { - deletePackageX(packageName, userHandle, 0); + deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST, + userHandle, 0); } //end run }); } @@ -21631,7 +22461,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); // after this method returns. mHandler.post(new Runnable() { public void run() { - deletePackageX(packageName, 0, PackageManager.DELETE_ALL_USERS); + deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST, + 0, PackageManager.DELETE_ALL_USERS); } }); } diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 2751742ff875..aa421b121640 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -40,6 +40,7 @@ import android.content.pm.PermissionInfo; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.ResolveInfo; +import android.content.pm.VersionedPackage; import android.content.res.AssetManager; import android.content.res.Resources; import android.net.Uri; @@ -663,7 +664,8 @@ class PackageManagerShellCommand extends ShellCommand { pw.print(info.applicationInfo.sourceDir); pw.print("="); } - pw.print(info.packageName); + pw.print(info.packageName); pw.print( " versionCode:" + + info.applicationInfo.versionCode); if (listInstaller) { pw.print(" installer="); pw.print(mInterface.getInstallerPackageName(info.packageName)); @@ -770,6 +772,7 @@ class PackageManagerShellCommand extends ShellCommand { final PrintWriter pw = getOutPrintWriter(); int flags = 0; int userId = UserHandle.USER_ALL; + int versionCode = PackageManager.VERSION_CODE_HIGHEST; String opt; while ((opt = getNextOption()) != null) { @@ -780,6 +783,9 @@ class PackageManagerShellCommand extends ShellCommand { case "--user": userId = UserHandle.parseUserArg(getNextArgRequired()); break; + case "--versionCode": + versionCode = Integer.parseInt(getNextArgRequired()); + break; default: pw.println("Error: Unknown option: " + opt); return 1; @@ -819,7 +825,8 @@ class PackageManagerShellCommand extends ShellCommand { } final LocalIntentReceiver receiver = new LocalIntentReceiver(); - mInterface.getPackageInstaller().uninstall(packageName, null /*callerPackageName*/, flags, + mInterface.getPackageInstaller().uninstall(new VersionedPackage(packageName, + versionCode), null /*callerPackageName*/, flags, receiver.getIntentSender(), userId); final Intent result = receiver.getResult(); diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 80a398afdc80..5f348abd3b8d 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -46,10 +46,12 @@ final class PackageSetting extends PackageSettingBase { String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, String cpuAbiOverrideString, int pVersionCode, int pkgFlags, int privateFlags, String parentPackageName, - List<String> childPackageNames, int sharedUserId) { + List<String> childPackageNames, int sharedUserId, String[] usesStaticLibraries, + int[] usesStaticLibrariesVersions) { super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, - pVersionCode, pkgFlags, privateFlags, parentPackageName, childPackageNames); + pVersionCode, pkgFlags, privateFlags, parentPackageName, childPackageNames, + usesStaticLibraries, usesStaticLibrariesVersions); this.sharedUserId = sharedUserId; } diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index b332fa5c6f9b..b63edfdd0d73 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -32,6 +32,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Set; @@ -68,6 +69,9 @@ abstract class PackageSettingBase extends SettingBase { File resourcePath; String resourcePathString; + String[] usesStaticLibraries; + int[] usesStaticLibrariesVersions; + /** * The path under which native libraries have been unpacked. This path is * always derived at runtime, and is only stored here for cleanup when a @@ -139,13 +143,16 @@ abstract class PackageSettingBase extends SettingBase { String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, String cpuAbiOverrideString, int pVersionCode, int pkgFlags, int pkgPrivateFlags, - String parentPackageName, List<String> childPackageNames) { + String parentPackageName, List<String> childPackageNames, + String[] usesStaticLibraries, int[] usesStaticLibrariesVersions) { super(pkgFlags, pkgPrivateFlags); this.name = name; this.realName = realName; this.parentPackageName = parentPackageName; this.childPackageNames = (childPackageNames != null) ? new ArrayList<>(childPackageNames) : null; + this.usesStaticLibraries = usesStaticLibraries; + this.usesStaticLibrariesVersions = usesStaticLibrariesVersions; init(codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, pVersionCode); } @@ -250,6 +257,12 @@ abstract class PackageSettingBase extends SettingBase { versionCode = orig.versionCode; volumeUuid = orig.volumeUuid; categoryHint = orig.categoryHint; + usesStaticLibraries = orig.usesStaticLibraries != null + ? Arrays.copyOf(orig.usesStaticLibraries, + orig.usesStaticLibraries.length) : null; + usesStaticLibrariesVersions = orig.usesStaticLibrariesVersions != null + ? Arrays.copyOf(orig.usesStaticLibrariesVersions, + orig.usesStaticLibrariesVersions.length) : null; } private PackageUserState modifyUserState(int userId) { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 8761a6dc60c1..281e445e59b4 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -183,6 +183,7 @@ final class Settings { private static final String TAG_RUNTIME_PERMISSIONS = "runtime-permissions"; private static final String TAG_PERMISSIONS = "perms"; private static final String TAG_CHILD_PACKAGE = "child-package"; + private static final String TAG_USES_STATIC_LIB = "uses-static-lib"; private static final String TAG_PERSISTENT_PREFERRED_ACTIVITIES = "persistent-preferred-activities"; @@ -201,6 +202,7 @@ final class Settings { private static final String ATTR_CODE = "code"; private static final String ATTR_GRANTED = "granted"; private static final String ATTR_FLAGS = "flags"; + private static final String ATTR_VERSION = "version"; private static final String ATTR_CE_DATA_INODE = "ceDataInode"; private static final String ATTR_INSTALLED = "inst"; @@ -561,7 +563,8 @@ final class Settings { p.legacyNativeLibraryPathString, p.primaryCpuAbiString, p.secondaryCpuAbiString, p.cpuAbiOverrideString, p.appId, p.versionCode, p.pkgFlags, p.pkgPrivateFlags, - p.parentPackageName, p.childPackageNames); + p.parentPackageName, p.childPackageNames, p.usesStaticLibraries, + p.usesStaticLibrariesVersions); mDisabledSysPackages.remove(name); return ret; } @@ -578,7 +581,8 @@ final class Settings { String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, int vc, int pkgFlags, int pkgPrivateFlags, String parentPackageName, - List<String> childPackageNames) { + List<String> childPackageNames, String[] usesStaticLibraries, + int[] usesStaticLibraryNames) { PackageSetting p = mPackages.get(name); if (p != null) { if (p.appId == uid) { @@ -591,7 +595,7 @@ final class Settings { p = new PackageSetting(name, realName, codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags, parentPackageName, - childPackageNames, 0 /*userId*/); + childPackageNames, 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames); p.appId = uid; if (addUserIdLPw(uid, p, name)) { mPackages.put(name, p); @@ -678,7 +682,8 @@ final class Settings { File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi, String secondaryCpuAbi, int versionCode, int pkgFlags, int pkgPrivateFlags, UserHandle installUser, boolean allowInstall, String parentPkgName, - List<String> childPkgNames, UserManagerService userManager) { + List<String> childPkgNames, UserManagerService userManager, + String[] usesStaticLibraries, int[] usesStaticLibrariesVersions) { final PackageSetting pkgSetting; if (originalPkg != null) { if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package " @@ -699,13 +704,16 @@ final class Settings { // overwrite the signatures in the original package setting. pkgSetting.signatures = new PackageSignatures(); pkgSetting.versionCode = versionCode; + pkgSetting.usesStaticLibraries = usesStaticLibraries; + pkgSetting.usesStaticLibrariesVersions = usesStaticLibrariesVersions; // Update new package state. pkgSetting.setTimeStamp(codePath.lastModified()); } else { pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, resourcePath, legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi, null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags, - parentPkgName, childPkgNames, 0 /*sharedUserId*/); + parentPkgName, childPkgNames, 0 /*sharedUserId*/, usesStaticLibraries, + usesStaticLibrariesVersions); pkgSetting.setTimeStamp(codePath.lastModified()); pkgSetting.sharedUser = sharedUser; // If this is not a system app, it starts out stopped. @@ -782,7 +790,8 @@ final class Settings { @NonNull File codePath, @Nullable String legacyNativeLibraryPath, @Nullable String primaryCpuAbi, @Nullable String secondaryCpuAbi, int pkgFlags, int pkgPrivateFlags, @Nullable List<String> childPkgNames, - @NonNull UserManagerService userManager) throws PackageManagerException { + @NonNull UserManagerService userManager, @Nullable String[] usesStaticLibraries, + @Nullable int[] usesStaticLibrariesVersions) throws PackageManagerException { final String pkgName = pkgSetting.name; if (pkgSetting.sharedUser != sharedUser) { PackageManagerService.reportSettingsProblem(Log.WARN, @@ -844,6 +853,14 @@ final class Settings { if (childPkgNames != null) { pkgSetting.childPackageNames = new ArrayList<>(childPkgNames); } + if (usesStaticLibraries != null) { + pkgSetting.usesStaticLibraries = Arrays.copyOf(usesStaticLibraries, + usesStaticLibraries.length); + } + if (usesStaticLibrariesVersions != null) { + pkgSetting.usesStaticLibrariesVersions = Arrays.copyOf(usesStaticLibrariesVersions, + usesStaticLibrariesVersions.length); + } } /** @@ -949,6 +966,16 @@ final class Settings { if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) { p.sharedUser.signatures.assignSignatures(pkg.mSignatures); } + // Update static shared library dependencies if needed + if (pkg.usesStaticLibraries != null && pkg.usesStaticLibrariesVersions != null + && pkg.usesStaticLibraries.size() == pkg.usesStaticLibrariesVersions.length) { + String[] usesStaticLibraries = new String[pkg.usesStaticLibraries.size()]; + pkg.usesStaticLibraries.toArray(usesStaticLibraries); + p.usesStaticLibrariesVersions = pkg.usesStaticLibrariesVersions; + } else { + pkg.usesStaticLibraries = null; + p.usesStaticLibrariesVersions = null; + } addPackageSettingLPw(p, p.sharedUser); } @@ -2163,6 +2190,53 @@ final class Settings { } } + void readUsesStaticLibLPw(XmlPullParser parser, PackageSetting outPs) + throws IOException, XmlPullParserException { + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + String libName = parser.getAttributeValue(null, ATTR_NAME); + String libVersionStr = parser.getAttributeValue(null, ATTR_VERSION); + + int libVersion = -1; + try { + libVersion = Integer.parseInt(libVersionStr); + } catch (NumberFormatException e) { + // ignore + } + + if (libName != null && libVersion >= 0) { + outPs.usesStaticLibraries = ArrayUtils.appendElement(String.class, + outPs.usesStaticLibraries, libName); + outPs.usesStaticLibrariesVersions = ArrayUtils.appendInt( + outPs.usesStaticLibrariesVersions, libVersion); + } + + XmlUtils.skipCurrentTag(parser); + } + } + + void writeUsesStaticLibLPw(XmlSerializer serializer, String[] usesStaticLibraries, + int[] usesStaticLibraryVersions) throws IOException { + if (ArrayUtils.isEmpty(usesStaticLibraries) || ArrayUtils.isEmpty(usesStaticLibraryVersions) + || usesStaticLibraries.length != usesStaticLibraryVersions.length) { + return; + } + final int libCount = usesStaticLibraries.length; + for (int i = 0; i < libCount; i++) { + final String libName = usesStaticLibraries[i]; + final int libVersion = usesStaticLibraryVersions[i]; + serializer.startTag(null, TAG_USES_STATIC_LIB); + serializer.attribute(null, ATTR_NAME, libName); + serializer.attribute(null, ATTR_VERSION, Integer.toString(libVersion)); + serializer.endTag(null, TAG_USES_STATIC_LIB); + } + } + // Note: assumed "stopped" field is already cleared in all packages. // Legacy reader, used to read in the old file format after an upgrade. Not used after that. void readStoppedLPw() { @@ -2622,6 +2696,8 @@ final class Settings { writeChildPackagesLPw(serializer, pkg.childPackageNames); + writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions); + // If this is a shared user, the permissions will be written there. if (pkg.sharedUser == null) { writePermissionsLPr(serializer, pkg.getPermissionsState() @@ -2692,6 +2768,8 @@ final class Settings { writeChildPackagesLPw(serializer, pkg.childPackageNames); + writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions); + pkg.signatures.writeXml(serializer, "sigs", mPastSignatures); writePermissionsLPr(serializer, pkg.getPermissionsState() @@ -3465,7 +3543,7 @@ final class Settings { PackageSetting ps = new PackageSetting(name, realName, codePathFile, new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr, secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags, - parentPackageName, null /*childPackageNames*/, 0 /*sharedUserId*/); + parentPackageName, null /*childPackageNames*/, 0 /*sharedUserId*/, null, null); String timeStampStr = parser.getAttributeValue(null, "ft"); if (timeStampStr != null) { try { @@ -3520,6 +3598,8 @@ final class Settings { ps.childPackageNames = new ArrayList<>(); } ps.childPackageNames.add(childPackageName); + } else if (parser.getName().equals(TAG_USES_STATIC_LIB)) { + readUsesStaticLibLPw(parser, ps); } else { PackageManagerService.reportSettingsProblem(Log.WARN, "Unknown element under <updated-package>: " + parser.getName()); @@ -3705,7 +3785,8 @@ final class Settings { packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags, - pkgPrivateFlags, parentPackageName, null /*childPackageNames*/); + pkgPrivateFlags, parentPackageName, null /*childPackageNames*/, + null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/); if (PackageManagerService.DEBUG_SETTINGS) Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId=" + userId + " pkg=" + packageSetting); @@ -3724,7 +3805,8 @@ final class Settings { codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, versionCode, pkgFlags, pkgPrivateFlags, parentPackageName, - null /*childPackageNames*/, sharedUserId); + null /*childPackageNames*/, sharedUserId, + null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/); packageSetting.setTimeStamp(timeStamp); packageSetting.firstInstallTime = firstInstallTime; packageSetting.lastUpdateTime = lastUpdateTime; @@ -4294,6 +4376,7 @@ final class Settings { ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_EXPLICITLY_SET, "RESIZEABLE_ACTIVITIES_EXPLICITLY_SET", ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_VIA_SDK_VERSION, "RESIZEABLE_ACTIVITIES_VIA_SDK_VERSION", ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND, "BACKUP_IN_FOREGROUND", + ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY, "STATIC_SHARED_LIBRARY", }; void dumpVersionLPr(IndentingPrintWriter pw) { @@ -4486,23 +4569,39 @@ final class Settings { } pw.println("]"); if (ps.pkg.libraryNames != null && ps.pkg.libraryNames.size() > 0) { - pw.print(prefix); pw.println(" libraries:"); - for (int i=0; i<ps.pkg.libraryNames.size(); i++) { - pw.print(prefix); pw.print(" "); pw.println(ps.pkg.libraryNames.get(i)); + pw.print(prefix); pw.println(" dynamic libraries:"); + for (int i = 0; i<ps.pkg.libraryNames.size(); i++) { + pw.print(prefix); pw.print(" "); + pw.println(ps.pkg.libraryNames.get(i)); } } + if (ps.pkg.staticSharedLibName != null) { + pw.print(prefix); pw.println(" static library:"); + pw.print(prefix); pw.print(" "); + pw.print("name:"); pw.print(ps.pkg.staticSharedLibName); + pw.print(" version:"); pw.println(ps.pkg.staticSharedLibVersion); + } if (ps.pkg.usesLibraries != null && ps.pkg.usesLibraries.size() > 0) { pw.print(prefix); pw.println(" usesLibraries:"); for (int i=0; i<ps.pkg.usesLibraries.size(); i++) { pw.print(prefix); pw.print(" "); pw.println(ps.pkg.usesLibraries.get(i)); } } + if (ps.pkg.usesStaticLibraries != null + && ps.pkg.usesStaticLibraries.size() > 0) { + pw.print(prefix); pw.println(" usesStaticLibraries:"); + for (int i=0; i<ps.pkg.usesStaticLibraries.size(); i++) { + pw.print(prefix); pw.print(" "); + pw.print(ps.pkg.usesStaticLibraries.get(i)); pw.print(" version:"); + pw.println(ps.pkg.usesStaticLibrariesVersions[i]); + } + } if (ps.pkg.usesOptionalLibraries != null && ps.pkg.usesOptionalLibraries.size() > 0) { pw.print(prefix); pw.println(" usesOptionalLibraries:"); for (int i=0; i<ps.pkg.usesOptionalLibraries.size(); i++) { pw.print(prefix); pw.print(" "); - pw.println(ps.pkg.usesOptionalLibraries.get(i)); + pw.println(ps.pkg.usesOptionalLibraries.get(i)); } } if (ps.pkg.usesLibraryFiles != null diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java index 64c562278227..fec3267c2649 100644 --- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java @@ -39,7 +39,8 @@ public class KeySetManagerServiceTest extends AndroidTestCase { public PackageSetting generateFakePackageSetting(String name) { return new PackageSetting(name, name, new File(mContext.getCacheDir(), "fakeCodePath"), new File(mContext.getCacheDir(), "fakeResPath"), "", "", "", - "", 1, 0, 0, null, null, 0 /*sharedUserId*/); + "", 1, 0, 0, null, null, 0 /*sharedUserId*/, null /*usesStaticLibraries*/, + null /*usesStaticLibrariesVersions*/); } @Override diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index bd2bb6c2b842..baf60c539105 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -216,7 +216,9 @@ public class PackageManagerSettingsTests { ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN, PARENT_PACKAGE_NAME, childPackageNames, - 0); + 0, + null /*usesStaticLibraries*/, + null /*usesStaticLibrariesVersions*/); final PackageSetting testPkgSetting01 = new PackageSetting(origPkgSetting01); verifySettingCopy(origPkgSetting01, testPkgSetting01); } @@ -241,7 +243,9 @@ public class PackageManagerSettingsTests { ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN, PARENT_PACKAGE_NAME, childPackageNames, - 0); + 0, + null /*usesStaticLibraries*/, + null /*usesStaticLibrariesVersions*/); final PackageSetting testPkgSetting01 = new PackageSetting( PACKAGE_NAME /*pkgName*/, REAL_PACKAGE_NAME /*realPkgName*/, @@ -256,7 +260,9 @@ public class PackageManagerSettingsTests { 0 /*pkgPrivateFlags*/, null /*parentPkgName*/, null /*childPkgNames*/, - 0); + 0, + null /*usesStaticLibraries*/, + null /*usesStaticLibrariesVersions*/); testPkgSetting01.copyFrom(origPkgSetting01); verifySettingCopy(origPkgSetting01, testPkgSetting01); } @@ -281,7 +287,9 @@ public class PackageManagerSettingsTests { 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, null /*childPkgNames*/, - UserManagerService.getInstance()); + UserManagerService.getInstance(), + null /*usesStaticLibraries*/, + null /*usesStaticLibrariesVersions*/); assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a")); assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi")); assertThat(testPkgSetting01.origPackage, is(nullValue())); @@ -313,7 +321,9 @@ public class PackageManagerSettingsTests { ApplicationInfo.FLAG_SYSTEM /*pkgFlags*/, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED /*pkgPrivateFlags*/, null /*childPkgNames*/, - UserManagerService.getInstance()); + UserManagerService.getInstance(), + null /*usesStaticLibraries*/, + null /*usesStaticLibrariesVersions*/); assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a")); assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi")); assertThat(testPkgSetting01.origPackage, is(nullValue())); @@ -348,7 +358,9 @@ public class PackageManagerSettingsTests { 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, null /*childPkgNames*/, - UserManagerService.getInstance()); + UserManagerService.getInstance(), + null /*usesStaticLibraries*/, + null /*usesStaticLibrariesVersions*/); fail("Expected a PackageManagerException"); } catch (PackageManagerException expected) { } @@ -378,7 +390,9 @@ public class PackageManagerSettingsTests { false /*allowInstall*/, null /*parentPkgName*/, null /*childPkgNames*/, - UserManagerService.getInstance()); + UserManagerService.getInstance(), + null /*usesStaticLibraries*/, + null /*usesStaticLibrariesVersions*/); assertThat(testPkgSetting01.codePath, is(UPDATED_CODE_PATH)); assertThat(testPkgSetting01.name, is(PACKAGE_NAME)); assertThat(testPkgSetting01.pkgFlags, is(ApplicationInfo.FLAG_SYSTEM)); @@ -416,7 +430,9 @@ public class PackageManagerSettingsTests { true /*allowInstall*/, null /*parentPkgName*/, null /*childPkgNames*/, - UserManagerService.getInstance()); + UserManagerService.getInstance(), + null /*usesStaticLibraries*/, + null /*usesStaticLibrariesVersions*/); assertThat(testPkgSetting01.appId, is(0)); assertThat(testPkgSetting01.codePath, is(INITIAL_CODE_PATH)); assertThat(testPkgSetting01.name, is(PACKAGE_NAME)); @@ -457,7 +473,9 @@ public class PackageManagerSettingsTests { false /*allowInstall*/, null /*parentPkgName*/, null /*childPkgNames*/, - UserManagerService.getInstance()); + UserManagerService.getInstance(), + null /*usesStaticLibraries*/, + null /*usesStaticLibrariesVersions*/); assertThat(testPkgSetting01.appId, is(10064)); assertThat(testPkgSetting01.codePath, is(INITIAL_CODE_PATH)); assertThat(testPkgSetting01.name, is(PACKAGE_NAME)); @@ -498,7 +516,9 @@ public class PackageManagerSettingsTests { false /*allowInstall*/, null /*parentPkgName*/, null /*childPkgNames*/, - UserManagerService.getInstance()); + UserManagerService.getInstance(), + null /*usesStaticLibraries*/, + null /*usesStaticLibrariesVersions*/); assertThat(testPkgSetting01.appId, is(10064)); assertThat(testPkgSetting01.codePath, is(UPDATED_CODE_PATH)); assertThat(testPkgSetting01.name, is(PACKAGE_NAME)); @@ -624,7 +644,9 @@ public class PackageManagerSettingsTests { 0 /*privateFlags*/, null /*parentPackageName*/, null /*childPackageNames*/, - sharedUserId); + sharedUserId, + null /*usesStaticLibraries*/, + null /*usesStaticLibrariesVersions*/); } private @NonNull List<UserInfo> createFakeUsers() { diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index c46d4a5aff99..0c34f204a8cb 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -16,6 +16,7 @@ package android.test.mock; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.PackageInstallObserver; @@ -43,7 +44,9 @@ import android.content.pm.PermissionInfo; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.content.pm.SharedLibraryInfo; import android.content.pm.VerifierDeviceIdentity; +import android.content.pm.VersionedPackage; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.Rect; @@ -72,6 +75,12 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + @Override + public PackageInfo getPackageInfo(VersionedPackage versionedPackage, + int flags) throws NameNotFoundException { + throw new UnsupportedOperationException(); + } + /** @hide */ @Override public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId) @@ -715,8 +724,7 @@ public class MockPackageManager extends PackageManager { * @hide - to match hiding in superclass */ @Override - public void deletePackage( - String packageName, IPackageDeleteObserver observer, int flags) { + public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) { throw new UnsupportedOperationException(); } @@ -724,8 +732,8 @@ public class MockPackageManager extends PackageManager { * @hide - to match hiding in superclass */ @Override - public void deletePackageAsUser( - String packageName, IPackageDeleteObserver observer, int flags, int userId) { + public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, + int flags, int userId) { throw new UnsupportedOperationException(); } @@ -818,6 +826,17 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + @Override + public @NonNull List<SharedLibraryInfo> getSharedLibraries(int flags) { + throw new UnsupportedOperationException(); + } + + /** @hide */ + @Override + public @NonNull List<SharedLibraryInfo> getSharedLibrariesAsUser(int flags, int userId) { + throw new UnsupportedOperationException(); + } + /** @hide */ @Override public @NonNull String getServicesSystemSharedLibraryPackageName() { diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java index bc7bc74ae2c8..d3ec9e271ba4 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java @@ -42,14 +42,15 @@ import android.content.pm.PermissionInfo; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.content.pm.SharedLibraryInfo; import android.content.pm.VerifierDeviceIdentity; +import android.content.pm.VersionedPackage; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Handler; -import android.os.RemoteException; import android.os.UserHandle; import android.os.storage.VolumeInfo; import java.util.List; @@ -71,6 +72,23 @@ public class BridgePackageManager extends PackageManager { } @Override + public PackageInfo getPackageInfo(VersionedPackage versionedPackage, + @PackageInfoFlags int flags) throws NameNotFoundException { + return null; + } + + @Override + public List<SharedLibraryInfo> getSharedLibraries(@InstallFlags int flags) { + return null; + } + + @Override + public List<SharedLibraryInfo> getSharedLibrariesAsUser(@InstallFlags int flags, + int userId) { + return null; + } + + @Override public String[] currentToCanonicalPackageNames(String[] names) { return new String[0]; } |