diff options
61 files changed, 3197 insertions, 746 deletions
diff --git a/api/current.txt b/api/current.txt index 21f547912bc1..97019181111d 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 { @@ -10694,6 +10723,7 @@ package android.content.res { method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException; method public deprecated android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException; method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme); + method public android.graphics.Typeface getFont(int) throws android.content.res.Resources.NotFoundException; method public float getFraction(int, int, int); method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String); method public int[] getIntArray(int) throws android.content.res.Resources.NotFoundException; @@ -39175,6 +39205,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 +39220,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); @@ -49359,6 +49391,10 @@ package android.widget { method public void endBatchEdit(); method public boolean extractText(android.view.inputmethod.ExtractedTextRequest, android.view.inputmethod.ExtractedText); method public final int getAutoLinkMask(); + method public int getAutoSizeMaxTextSize(); + method public int getAutoSizeMinTextSize(); + method public int getAutoSizeStepGranularity(); + method public int getAutoSizeTextType(); method public int getBreakStrategy(); method public int getCompoundDrawablePadding(); method public android.content.res.ColorStateList getCompoundDrawableTintList(); @@ -49467,6 +49503,10 @@ package android.widget { method public void removeTextChangedListener(android.text.TextWatcher); method public void setAllCaps(boolean); method public final void setAutoLinkMask(int); + method public void setAutoSizeMaxTextSize(int, float); + method public void setAutoSizeMinTextSize(int, float); + method public void setAutoSizeStepGranularity(int, float); + method public void setAutoSizeTextType(int); method public void setBreakStrategy(int); method public void setCompoundDrawablePadding(int); method public void setCompoundDrawableTintList(android.content.res.ColorStateList); @@ -49557,8 +49597,8 @@ package android.widget { method public void setTypeface(android.graphics.Typeface, int); method public void setTypeface(android.graphics.Typeface); method public void setWidth(int); - field public static final int AUTO_SIZE_TYPE_NONE = 0; // 0x0 - field public static final int AUTO_SIZE_TYPE_XY = 1; // 0x1 + field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0 + field public static final int AUTO_SIZE_TEXT_TYPE_XY = 1; // 0x1 } public static final class TextView.BufferType extends java.lang.Enum { diff --git a/api/system-current.txt b/api/system-current.txt index afc3d0928592..4cd63d694dcb 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 { @@ -11216,6 +11245,7 @@ package android.content.res { method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException; method public deprecated android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException; method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme); + method public android.graphics.Typeface getFont(int) throws android.content.res.Resources.NotFoundException; method public float getFraction(int, int, int); method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String); method public int[] getIntArray(int) throws android.content.res.Resources.NotFoundException; @@ -42444,6 +42474,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 +42490,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); @@ -52997,6 +53029,10 @@ package android.widget { method public void endBatchEdit(); method public boolean extractText(android.view.inputmethod.ExtractedTextRequest, android.view.inputmethod.ExtractedText); method public final int getAutoLinkMask(); + method public int getAutoSizeMaxTextSize(); + method public int getAutoSizeMinTextSize(); + method public int getAutoSizeStepGranularity(); + method public int getAutoSizeTextType(); method public int getBreakStrategy(); method public int getCompoundDrawablePadding(); method public android.content.res.ColorStateList getCompoundDrawableTintList(); @@ -53105,6 +53141,10 @@ package android.widget { method public void removeTextChangedListener(android.text.TextWatcher); method public void setAllCaps(boolean); method public final void setAutoLinkMask(int); + method public void setAutoSizeMaxTextSize(int, float); + method public void setAutoSizeMinTextSize(int, float); + method public void setAutoSizeStepGranularity(int, float); + method public void setAutoSizeTextType(int); method public void setBreakStrategy(int); method public void setCompoundDrawablePadding(int); method public void setCompoundDrawableTintList(android.content.res.ColorStateList); @@ -53195,8 +53235,8 @@ package android.widget { method public void setTypeface(android.graphics.Typeface, int); method public void setTypeface(android.graphics.Typeface); method public void setWidth(int); - field public static final int AUTO_SIZE_TYPE_NONE = 0; // 0x0 - field public static final int AUTO_SIZE_TYPE_XY = 1; // 0x1 + field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0 + field public static final int AUTO_SIZE_TEXT_TYPE_XY = 1; // 0x1 } public static final class TextView.BufferType extends java.lang.Enum { diff --git a/api/test-current.txt b/api/test-current.txt index 621045a89baf..1aa70ebbb74a 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 { @@ -10726,6 +10755,7 @@ package android.content.res { method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException; method public deprecated android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException; method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme); + method public android.graphics.Typeface getFont(int) throws android.content.res.Resources.NotFoundException; method public float getFraction(int, int, int); method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String); method public int[] getIntArray(int) throws android.content.res.Resources.NotFoundException; @@ -39299,6 +39329,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 +39344,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); @@ -49664,6 +49696,10 @@ package android.widget { method public void endBatchEdit(); method public boolean extractText(android.view.inputmethod.ExtractedTextRequest, android.view.inputmethod.ExtractedText); method public final int getAutoLinkMask(); + method public int getAutoSizeMaxTextSize(); + method public int getAutoSizeMinTextSize(); + method public int getAutoSizeStepGranularity(); + method public int getAutoSizeTextType(); method public int getBreakStrategy(); method public int getCompoundDrawablePadding(); method public android.content.res.ColorStateList getCompoundDrawableTintList(); @@ -49772,6 +49808,10 @@ package android.widget { method public void removeTextChangedListener(android.text.TextWatcher); method public void setAllCaps(boolean); method public final void setAutoLinkMask(int); + method public void setAutoSizeMaxTextSize(int, float); + method public void setAutoSizeMinTextSize(int, float); + method public void setAutoSizeStepGranularity(int, float); + method public void setAutoSizeTextType(int); method public void setBreakStrategy(int); method public void setCompoundDrawablePadding(int); method public void setCompoundDrawableTintList(android.content.res.ColorStateList); @@ -49862,8 +49902,8 @@ package android.widget { method public void setTypeface(android.graphics.Typeface, int); method public void setTypeface(android.graphics.Typeface); method public void setWidth(int); - field public static final int AUTO_SIZE_TYPE_NONE = 0; // 0x0 - field public static final int AUTO_SIZE_TYPE_XY = 1; // 0x1 + field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0 + field public static final int AUTO_SIZE_TEXT_TYPE_XY = 1; // 0x1 } public static final class TextView.BufferType extends java.lang.Enum { 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/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index ad113075c96b..c3185a7cad05 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -40,6 +40,7 @@ import android.annotation.StyleableRes; import android.annotation.XmlRes; import android.content.pm.ActivityInfo; import android.graphics.Movie; +import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable.ConstantState; import android.graphics.drawable.DrawableInflater; @@ -333,7 +334,35 @@ public class Resources { return res; } throw new NotFoundException("String resource ID #0x" - + Integer.toHexString(id)); + + Integer.toHexString(id)); + } + + /** + * Return the Typeface value associated with a particular resource ID. + * {@more} + * + * @param id The desired resource identifier, as generated by the aapt + * tool. This integer encodes the package, type, and resource + * entry. The value 0 is an invalid identifier. + * + * @throws NotFoundException Throws NotFoundException if the given ID does not exist. + * + * @return Typeface The Typeface data associated with the resource. + */ + @NonNull public Typeface getFont(@StringRes int id) throws NotFoundException { + final TypedValue value = obtainTempTypedValue(); + try { + final ResourcesImpl impl = mResourcesImpl; + impl.getValue(id, value, true); + Typeface typeface = impl.loadFont(value, id); + if (typeface != null) { + return typeface; + } + } finally { + releaseTempTypedValue(value); + } + throw new NotFoundException("Font resource ID #0x" + + Integer.toHexString(id)); } /** diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index eb010e46ea91..05892e0ad660 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -31,6 +31,7 @@ import android.annotation.StyleableRes; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo.Config; import android.content.res.Resources.NotFoundException; +import android.graphics.Typeface; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.icu.text.PluralRules; @@ -47,6 +48,7 @@ import android.util.Xml; import android.view.Display; import android.view.DisplayAdjustments; +import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.Locale; @@ -740,6 +742,36 @@ public class ResourcesImpl { } /** + * Loads a font from XML or resources stream. + */ + @Nullable + public Typeface loadFont(TypedValue value, int id) { + if (value.string == null) { + throw new NotFoundException("Resource \"" + getResourceName(id) + "\" (" + + Integer.toHexString(id) + ") is not a Font: " + value); + } + + final String file = value.string.toString(); + + if (DEBUG_LOAD) { + Log.v(TAG, "Loading font for cookie " + value.assetCookie + ": " + file); + } + + Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); + try { + if (file.endsWith(".xml")) { + // TODO handle xml type font definitions + } else { + return Typeface.createFromResources( + mAssets, value.string.toString(), value.assetCookie); + } + } finally { + Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); + } + return null; + } + + /** * Given the value and id, we can get the XML filename as in value.data, based on that, we * first try to load CSL from the cache. If not found, try to get from the constant state. * Last, parse the XML and generate the CSL. diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl index 59394b2c58d7..b03c9070dc44 100644 --- a/core/java/android/os/storage/IStorageManager.aidl +++ b/core/java/android/os/storage/IStorageManager.aidl @@ -286,7 +286,6 @@ interface IStorageManager { void prepareUserStorage(in String volumeUuid, int userId, int serialNumber, int flags) = 66; void destroyUserStorage(in String volumeUuid, int userId, int flags) = 67; boolean isConvertibleToFBE() = 68; - ParcelFileDescriptor mountAppFuse(in String name) = 69; void addUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 70; void fixateNewestUserKeyAuth(int userId) = 71; void fstrim(int flags) = 72; diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 85df48f91a5a..c6ff47694bab 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -1319,16 +1319,6 @@ public class StorageManager { } /** {@hide} */ - public ParcelFileDescriptor mountAppFuse(String name) { - try { - return mStorageManager.mountAppFuse(name); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - - /** {@hide} */ @VisibleForTesting public @NonNull ParcelFileDescriptor openProxyFileDescriptor( int mode, ProxyFileDescriptorCallback callback, ThreadFactory factory) diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java index af5c8426a44a..faf037964897 100644 --- a/core/java/android/widget/EditText.java +++ b/core/java/android/widget/EditText.java @@ -42,6 +42,8 @@ import android.view.autofill.AutoFillValue; * <p>See the <a href="{@docRoot}guide/topics/ui/controls/text.html">Text Fields</a> * guide.</p> * <p> + * This widget does not support auto-sizing text. + * <p> * <b>XML attributes</b> * <p> * See {@link android.R.styleable#EditText EditText Attributes}, diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 08b18a4e5313..b1fc67e56d80 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -22,6 +22,7 @@ import android.R; import android.annotation.ColorInt; import android.annotation.DrawableRes; import android.annotation.FloatRange; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; @@ -158,6 +159,8 @@ import com.android.internal.widget.EditableInputConnection; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Locale; @@ -252,6 +255,10 @@ import java.util.Locale; * @attr ref android.R.styleable#TextView_fontFeatureSettings * @attr ref android.R.styleable#TextView_breakStrategy * @attr ref android.R.styleable#TextView_hyphenationFrequency + * @attr ref android.R.styleable#TextView_autoSizeText + * @attr ref android.R.styleable#TextView_autoSizeMinTextSize + * @attr ref android.R.styleable#TextView_autoSizeMaxTextSize + * @attr ref android.R.styleable#TextView_autoSizeStepGranularity */ @RemoteView public class TextView extends View implements ViewTreeObserver.OnPreDrawListener { @@ -670,17 +677,31 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ private int mDeviceProvisionedState = DEVICE_PROVISIONED_UNKNOWN; - // The TextView does not auto-size text. - public static final int AUTO_SIZE_TYPE_NONE = 0; + // The TextView does not auto-size text (default). + public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // The TextView performs uniform horizontal and vertical text size scaling to fit within the // container. - public static final int AUTO_SIZE_TYPE_XY = 1; - // Auto-size type. - private int mAutoSizeType = AUTO_SIZE_TYPE_NONE; - // Specify if auto-size is needed. - private boolean mNeedsAutoSize = false; + public static final int AUTO_SIZE_TEXT_TYPE_XY = 1; + /** @hide */ + @IntDef({AUTO_SIZE_TEXT_TYPE_NONE, AUTO_SIZE_TEXT_TYPE_XY}) + @Retention(RetentionPolicy.SOURCE) + public @interface AutoSizeTextType {} + // Default minimum size for auto-sizing text in scaled pixels. {@see #setAutoSizeMinTextSize}. + private static final int DEFAULT_AUTO_SIZE_MIN_TEXT_SIZE_IN_SP = 12; + // Default maximum size for auto-sizing text in scaled pixels. {@see #setAutoSizeMaxTextSize}. + private static final int DEFAULT_AUTO_SIZE_MAX_TEXT_SIZE_IN_SP = 112; // Default value for the step size in pixels. private static final int DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX = 1; + // Auto-size text type. + private int mAutoSizeTextType = AUTO_SIZE_TEXT_TYPE_NONE; + // Specify if auto-size text is needed. + private boolean mNeedsAutoSizeText = false; + // Step size for auto-sizing in pixels. + private int mAutoSizeStepGranularityInPx = 0; + // Minimum text size for auto-sizing in pixels. + private int mAutoSizeMinTextSizeInPx = 0; + // Maximum text size for auto-sizing in pixels. + private int mAutoSizeMaxTextSizeInPx = 0; // Contains the sorted set of desired text sizes in pixels to pick from when auto-sizing text. private int[] mAutoSizeTextSizesInPx; @@ -887,13 +908,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener CharSequence hint = null; boolean password = false; int inputType = EditorInfo.TYPE_NULL; - int autoSizeStepGranularityInPx = DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX; - int autoSizeMinTextSize = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_SP, 12, getResources().getDisplayMetrics()); - int autoSizeMaxTextSize = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_SP, 112, getResources().getDisplayMetrics()); - - a = theme.obtainStyledAttributes( attrs, com.android.internal.R.styleable.TextView, defStyleAttr, defStyleRes); @@ -1249,20 +1263,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener break; case com.android.internal.R.styleable.TextView_autoSizeText: - mAutoSizeType = a.getInt(attr, AUTO_SIZE_TYPE_NONE); + mAutoSizeTextType = a.getInt(attr, AUTO_SIZE_TEXT_TYPE_NONE); break; case com.android.internal.R.styleable.TextView_autoSizeStepGranularity: - autoSizeStepGranularityInPx = a.getDimensionPixelSize( - attr, DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX); + mAutoSizeStepGranularityInPx = a.getDimensionPixelSize(attr, 0); break; case com.android.internal.R.styleable.TextView_autoSizeMinTextSize: - autoSizeMinTextSize = a.getDimensionPixelSize(attr, autoSizeMinTextSize); + mAutoSizeMinTextSizeInPx = a.getDimensionPixelSize(attr, 0); break; case com.android.internal.R.styleable.TextView_autoSizeMaxTextSize: - autoSizeMaxTextSize = a.getDimensionPixelSize(attr, autoSizeMaxTextSize); + mAutoSizeMaxTextSizeInPx = a.getDimensionPixelSize(attr, 0); break; } } @@ -1542,39 +1555,204 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } - // Setup auto-size. - if (supportsAutoSizeText()) { - switch (mAutoSizeType) { - case AUTO_SIZE_TYPE_NONE: - // Nothing to do. - break; - case AUTO_SIZE_TYPE_XY: - if (autoSizeMaxTextSize <= autoSizeMinTextSize) { - throw new IllegalStateException("Maximum text size is less then minimum " - + "text size"); - } + setupAutoSizeTextXY(); + } - if (autoSizeStepGranularityInPx <= 0) { - throw new IllegalStateException("Unexpected zero or negative value for auto" - + " size step granularity in pixels"); + /** + * Specify whether this widget should automatically scale the text to try to perfectly fit + * within the layout bounds by taking into account the auto-size configuration. + * + * @param autoSizeTextType the type of auto-size. Must be one of + * {@link TextView#AUTO_SIZE_TEXT_TYPE_NONE} or + * {@link TextView#AUTO_SIZE_TEXT_TYPE_XY} + * + * @attr ref android.R.styleable#TextView_autoSizeText + * + * @see #getAutoSizeTextType() + */ + public void setAutoSizeTextType(@AutoSizeTextType int autoSizeTextType) { + if (supportsAutoSizeText()) { + switch (autoSizeTextType) { + case AUTO_SIZE_TEXT_TYPE_NONE: + if (mAutoSizeTextType != AUTO_SIZE_TEXT_TYPE_NONE) { + // Clear all auto-size configuration + mAutoSizeTextType = AUTO_SIZE_TEXT_TYPE_NONE; + mAutoSizeMinTextSizeInPx = 0; + mAutoSizeMaxTextSizeInPx = 0; + mAutoSizeStepGranularityInPx = 0; + mAutoSizeTextSizesInPx = null; + mNeedsAutoSizeText = false; } - - final int autoSizeValuesLength = (autoSizeMaxTextSize - autoSizeMinTextSize) - / autoSizeStepGranularityInPx; - mAutoSizeTextSizesInPx = new int[autoSizeValuesLength]; - int sizeToAdd = autoSizeMinTextSize; - for (int i = 0; i < autoSizeValuesLength; i++) { - mAutoSizeTextSizesInPx[i] = sizeToAdd; - sizeToAdd += autoSizeStepGranularityInPx; + break; + case AUTO_SIZE_TEXT_TYPE_XY: + if (mAutoSizeTextType != AUTO_SIZE_TEXT_TYPE_XY) { + mAutoSizeTextType = AUTO_SIZE_TEXT_TYPE_XY; + setupAutoSizeTextXY(); } - - mNeedsAutoSize = true; break; default: throw new IllegalArgumentException( - "Unknown autoSizeText type: " + mAutoSizeType); + "Unknown auto-size text type: " + autoSizeTextType); } + } + } + + /** + * Returns the type of auto-size set for this widget. + * + * @return an {@code int} corresponding to one of the auto-size types: + * {@link TextView#AUTO_SIZE_TEXT_TYPE_NONE} or + * {@link TextView#AUTO_SIZE_TEXT_TYPE_XY} + * + * @attr ref android.R.styleable#TextView_autoSizeText + * + * @see #setAutoSizeTextType(int) + */ + @AutoSizeTextType + public int getAutoSizeTextType() { + return mAutoSizeTextType; + } + /** + * Sets the auto-size step granularity. It is used in conjunction with auto-size minimum + * and maximum text size in order to build the set of text sizes the system uses to choose + * from when auto-sizing. + * + * @param unit the desired dimension unit. See {@link TypedValue} for the possible + * dimension units + * @param size the desired size in the given units + * + * @attr ref android.R.styleable#TextView_autoSizeStepGranularity + * + * @see #getAutoSizeStepGranularity() + * @see #setAutoSizeMinTextSize(int, float) + * @see #setAutoSizeMaxTextSize(int, float) + */ + public void setAutoSizeStepGranularity(int unit, float size) { + if (supportsAutoSizeText()) { + mAutoSizeStepGranularityInPx = (int) TypedValue.applyDimension( + unit, size, getResources().getDisplayMetrics()); + setupAutoSizeTextXY(); + } + } + + /** + * @return the current auto-size step granularity in pixels. + * + * @see #setAutoSizeStepGranularity(int, float) + */ + public int getAutoSizeStepGranularity() { + return mAutoSizeStepGranularityInPx; + } + + /** + * Sets the minimum text size to be used in conjunction with auto-size maximum text size and + * auto-size step granularity in order to build the set of text sizes the system uses to choose + * from when auto-sizing. + * + * @param unit the desired dimension unit. See {@link TypedValue} for the possible + * dimension units + * @param size the desired size in the given units + * + * @attr ref android.R.styleable#TextView_autoSizeMinTextSize + * + * @see #getAutoSizeMinTextSize() + * @see #setAutoSizeMaxTextSize(int, float) + * @see #setAutoSizeStepGranularity(int, float) + */ + public void setAutoSizeMinTextSize(int unit, float size) { + if (supportsAutoSizeText()) { + mAutoSizeMinTextSizeInPx = (int) TypedValue.applyDimension( + unit, size, getResources().getDisplayMetrics()); + setupAutoSizeTextXY(); + } + } + + /** + * @return the current auto-size minimum text size in pixels (the default is 12sp). Note that + * if auto-size has not been configured this function returns {@code 0}. + * + * @see #setAutoSizeMinTextSize(int, float) + */ + public int getAutoSizeMinTextSize() { + return mAutoSizeMinTextSizeInPx; + } + + /** + * Sets the maximum text size to be used in conjunction with auto-size minimum text size and + * auto-size step granularity in order to build the set of text sizes the system uses to choose + * from when auto-sizing. + * + * @param unit the desired dimension unit. See {@link TypedValue} for the possible + * dimension units + * @param size the desired size in the given units + * + * @attr ref android.R.styleable#TextView_autoSizeMaxTextSize + * + * @see #getAutoSizeMaxTextSize() + * @see #setAutoSizeMinTextSize(int, float) + * @see #setAutoSizeStepGranularity(int, float) + */ + public void setAutoSizeMaxTextSize(int unit, float size) { + if (supportsAutoSizeText()) { + mAutoSizeMaxTextSizeInPx = (int) TypedValue.applyDimension( + unit, size, getResources().getDisplayMetrics()); + setupAutoSizeTextXY(); + } + } + + /** + * @return the current auto-size maximum text size in pixels (the default is 112sp). Note that + * if auto-size has not been configured this function returns {@code 0}. + * + * @see #setAutoSizeMaxTextSize(int, float) + */ + public int getAutoSizeMaxTextSize() { + return mAutoSizeMaxTextSizeInPx; + } + + private void setupAutoSizeTextXY() { + if (supportsAutoSizeText() && mAutoSizeTextType == AUTO_SIZE_TEXT_TYPE_XY) { + // Set valid defaults. + if (mAutoSizeMinTextSizeInPx <= 0) { + mAutoSizeMinTextSizeInPx = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, + DEFAULT_AUTO_SIZE_MIN_TEXT_SIZE_IN_SP, + getResources().getDisplayMetrics()); + } + + if (mAutoSizeMaxTextSizeInPx <= 0) { + mAutoSizeMaxTextSizeInPx = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, + DEFAULT_AUTO_SIZE_MAX_TEXT_SIZE_IN_SP, + getResources().getDisplayMetrics()); + } + + if (mAutoSizeStepGranularityInPx <= 0) { + mAutoSizeStepGranularityInPx = DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX; + } + + // Validate. + if (mAutoSizeMaxTextSizeInPx <= mAutoSizeMinTextSizeInPx) { + throw new IllegalStateException("Maximum auto-size text size (" + + mAutoSizeMaxTextSizeInPx + "px) is less or equal to minimum auto-size " + + "text size (" + mAutoSizeMinTextSizeInPx + "px)"); + } + + // Calculate sizes to choose from based on the current auto-size configuration. + final int autoSizeValuesLength = (int) Math.ceil( + (mAutoSizeMaxTextSizeInPx - mAutoSizeMinTextSizeInPx) + / mAutoSizeStepGranularityInPx); + + mAutoSizeTextSizesInPx = new int[autoSizeValuesLength]; + int sizeToAdd = mAutoSizeMinTextSizeInPx; + for (int i = 0; i < autoSizeValuesLength; i++) { + mAutoSizeTextSizesInPx[i] = sizeToAdd; + sizeToAdd += mAutoSizeStepGranularityInPx; + } + + mNeedsAutoSizeText = true; + autoSizeText(); } } @@ -3030,9 +3208,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * @return the size (in pixels) of the default text size in this TextView. - * - * <p>Note: if this TextView has mAutoSizeType set to {@link TextView#AUTO_SIZE_TYPE_XY} than - * this function returns the maximum text size for auto-sizing. */ @ViewDebug.ExportedProperty(category = "text") public float getTextSize() { @@ -3077,7 +3252,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Set the default text size to a given unit and value. See {@link + * Set the default text size to a given unit and value. See {@link * TypedValue} for the possible dimension units. * * <p>Note: if this TextView has the auto-size feature enabled than this function is no-op. @@ -3113,7 +3288,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mLayout != null) { // Do not auto-size right after setting the text size. - mNeedsAutoSize = false; + mNeedsAutoSizeText = false; nullLayouts(); requestLayout(); invalidate(); @@ -7563,13 +7738,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } if (isAutoSizeEnabled()) { - if (mNeedsAutoSize) { + if (mNeedsAutoSizeText) { // Call auto-size after the width and height have been calculated. autoSizeText(); } // Always try to auto-size if enabled. Functions that do not want to trigger auto-sizing // after the next measuring round should set this to false. - mNeedsAutoSize = true; + mNeedsAutoSizeText = true; } setMeasuredDimension(width, height); @@ -9328,7 +9503,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * auto-size. */ private boolean isAutoSizeEnabled() { - return supportsAutoSizeText() && mAutoSizeType != AUTO_SIZE_TYPE_NONE; + return supportsAutoSizeText() && mAutoSizeTextType != AUTO_SIZE_TEXT_TYPE_NONE; } /** diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp index 15e7165210ae..2504e540ff14 100644 --- a/core/jni/android/graphics/FontFamily.cpp +++ b/core/jni/android/graphics/FontFamily.cpp @@ -190,8 +190,8 @@ static void releaseAsset(const void* ptr, void* context) { delete static_cast<Asset*>(context); } -static jboolean FontFamily_addFontFromAsset(JNIEnv* env, jobject, jlong familyPtr, - jobject jassetMgr, jstring jpath) { +static jboolean FontFamily_addFontFromAssetManager(JNIEnv* env, jobject, jlong familyPtr, + jobject jassetMgr, jstring jpath, jint cookie, jboolean isAsset) { NPE_CHECK_RETURN_ZERO(env, jassetMgr); NPE_CHECK_RETURN_ZERO(env, jpath); @@ -201,7 +201,18 @@ static jboolean FontFamily_addFontFromAsset(JNIEnv* env, jobject, jlong familyPt } ScopedUtfChars str(env, jpath); - Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER); + if (str.c_str() == nullptr) { + return false; + } + + Asset* asset; + if (isAsset) { + asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER); + } else { + asset = cookie ? mgr->openNonAsset(static_cast<int32_t>(cookie), str.c_str(), + Asset::ACCESS_BUFFER) : mgr->openNonAsset(str.c_str(), Asset::ACCESS_BUFFER); + } + if (NULL == asset) { return false; } @@ -234,8 +245,8 @@ static const JNINativeMethod gFontFamilyMethods[] = { { "nAddFont", "(JLjava/nio/ByteBuffer;I)Z", (void*)FontFamily_addFont }, { "nAddFontWeightStyle", "(JLjava/nio/ByteBuffer;ILjava/util/List;IZ)Z", (void*)FontFamily_addFontWeightStyle }, - { "nAddFontFromAsset", "(JLandroid/content/res/AssetManager;Ljava/lang/String;)Z", - (void*)FontFamily_addFontFromAsset }, + { "nAddFontFromAssetManager", "(JLandroid/content/res/AssetManager;Ljava/lang/String;IZ)Z", + (void*)FontFamily_addFontFromAssetManager }, }; int register_android_graphics_FontFamily(JNIEnv* env) 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.xml b/core/res/res/values/attrs.xml index a40131469076..7c01dea63cee 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -4707,7 +4707,8 @@ screens with limited space for text. --> <enum name="full" value="2" /> </attr> - <!-- Specify the type of auto-size. --> + <!-- Specify the type of auto-size. Note that this feature is not supported by EditText, + works only for TextView --> <attr name="autoSizeText" format="enum"> <!-- No auto-sizing (default). --> <enum name="none" value="0" /> 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/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java index e48bf7956df3..cd5071e87e9e 100644 --- a/graphics/java/android/graphics/FontFamily.java +++ b/graphics/java/android/graphics/FontFamily.java @@ -85,8 +85,9 @@ public class FontFamily { return nAddFontWeightStyle(mNativePtr, font, ttcIndex, axes, weight, style); } - public boolean addFontFromAsset(AssetManager mgr, String path) { - return nAddFontFromAsset(mNativePtr, mgr, path); + public boolean addFontFromAssetManager(AssetManager mgr, String path, int cookie, + boolean isAsset) { + return nAddFontFromAssetManager(mNativePtr, mgr, path, cookie, isAsset); } private static native long nCreateFamily(String lang, int variant); @@ -95,6 +96,6 @@ public class FontFamily { private static native boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font, int ttcIndex, List<FontListParser.Axis> listOfAxis, int weight, boolean isItalic); - private static native boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr, - String path); + private static native boolean nAddFontFromAssetManager(long nativeFamily, AssetManager mgr, + String path, int cookie, boolean isAsset); } diff --git a/graphics/java/android/graphics/FontResourcesParser.java b/graphics/java/android/graphics/FontResourcesParser.java new file mode 100644 index 000000000000..b4109cfa3296 --- /dev/null +++ b/graphics/java/android/graphics/FontResourcesParser.java @@ -0,0 +1,113 @@ +/* + * 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.graphics; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +/** + * Parser for xml type font resources. + * @hide + */ +public class FontResourcesParser { + private static final String ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android"; + + /* Parse fallback list (no names) */ + public static FontListParser.Config parse(XmlPullParser parser) + throws XmlPullParserException, IOException { + int type; + //noinspection StatementWithEmptyBody + while ((type=parser.next()) != XmlPullParser.START_TAG + && type != XmlPullParser.END_DOCUMENT) { + // Empty loop. + } + + if (type != XmlPullParser.START_TAG) { + throw new XmlPullParserException("No start tag found"); + } + return readFamilies(parser); + } + + private static FontListParser.Config readFamilies(XmlPullParser parser) + throws XmlPullParserException, IOException { + FontListParser.Config config = new FontListParser.Config(); + parser.require(XmlPullParser.START_TAG, null, "font-family"); + String tag = parser.getName(); + if (tag.equals("font-family")) { + config.families.add(readFamily(parser)); + } else { + skip(parser); + } + return config; + } + + private static FontListParser.Family readFamily(XmlPullParser parser) + throws XmlPullParserException, IOException { + String name = parser.getAttributeValue(null, "name"); + String lang = parser.getAttributeValue(null, "lang"); + String variant = parser.getAttributeValue(null, "variant"); + List<FontListParser.Font> fonts = new ArrayList<>(); + while (parser.next() != XmlPullParser.END_TAG) { + if (parser.getEventType() != XmlPullParser.START_TAG) continue; + String tag = parser.getName(); + if (tag.equals("font")) { + fonts.add(readFont(parser)); + } else { + skip(parser); + } + } + return new FontListParser.Family(name, fonts, lang, variant); + } + + /** Matches leading and trailing XML whitespace. */ + private static final Pattern FILENAME_WHITESPACE_PATTERN = + Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$"); + + private static FontListParser.Font readFont(XmlPullParser parser) + throws XmlPullParserException, IOException { + + List<FontListParser.Axis> axes = new ArrayList<>(); + + String weightStr = parser.getAttributeValue(ANDROID_NAMESPACE, "fontWeight"); + int weight = weightStr == null ? 400 : Integer.parseInt(weightStr); + + boolean isItalic = "italic".equals( + parser.getAttributeValue(ANDROID_NAMESPACE, "fontStyle")); + + String filename = parser.getAttributeValue(ANDROID_NAMESPACE, "font"); + String fullFilename = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll(""); + return new FontListParser.Font(fullFilename, 0, axes, weight, isItalic); + } + + private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException { + int depth = 1; + while (depth > 0) { + switch (parser.next()) { + case XmlPullParser.START_TAG: + depth++; + break; + case XmlPullParser.END_TAG: + depth--; + break; + } + } + } +} diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 2886f0dd4a2e..eebe538ccab8 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -16,6 +16,7 @@ package android.graphics; +import android.annotation.NonNull; import android.content.res.AssetManager; import android.util.Log; import android.util.LongSparseArray; @@ -109,6 +110,30 @@ public class Typeface { } /** + * @hide + * Used by Resources. + */ + @NonNull + public static Typeface createFromResources(AssetManager mgr, String path, int cookie) { + if (sFallbackFonts != null) { + synchronized (sDynamicTypefaceCache) { + final String key = createAssetUid(mgr, path); + Typeface typeface = sDynamicTypefaceCache.get(key); + if (typeface != null) return typeface; + + FontFamily fontFamily = new FontFamily(); + if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */)) { + FontFamily[] families = { fontFamily }; + typeface = createFromFamiliesWithDefault(families); + sDynamicTypefaceCache.put(key, typeface); + return typeface; + } + } + } + throw new RuntimeException("Font resource not found " + path); + } + + /** * Create a typeface object given a family name, and option style information. * If null is passed for the name, then the "default" font will be chosen. * The resulting typeface object can be queried (getStyle()) to discover what @@ -195,7 +220,7 @@ public class Typeface { if (typeface != null) return typeface; FontFamily fontFamily = new FontFamily(); - if (fontFamily.addFontFromAsset(mgr, path)) { + if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */)) { FontFamily[] families = { fontFamily }; typeface = createFromFamiliesWithDefault(families); sDynamicTypefaceCache.put(key, typeface); diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java index 981939583e3b..bd0a1b42ce7d 100644 --- a/media/java/android/media/PlayerBase.java +++ b/media/java/android/media/PlayerBase.java @@ -78,6 +78,7 @@ public abstract class PlayerBase { } mAttributes = attr; mImplType = implType; + mState = AudioPlaybackConfiguration.PLAYER_STATE_IDLE; }; /** @@ -138,7 +139,8 @@ public abstract class PlayerBase { void baseStart() { if (DEBUG) { Log.v(TAG, "baseStart() piid=" + mPlayerIId); } try { - getService().playerEvent(mPlayerIId, AudioPlaybackConfiguration.PLAYER_STATE_STARTED); + mState = AudioPlaybackConfiguration.PLAYER_STATE_STARTED; + getService().playerEvent(mPlayerIId, mState); } catch (RemoteException e) { Log.e(TAG, "Error talking to audio service, STARTED state will not be tracked", e); } @@ -152,7 +154,8 @@ public abstract class PlayerBase { void basePause() { if (DEBUG) { Log.v(TAG, "basePause() piid=" + mPlayerIId); } try { - getService().playerEvent(mPlayerIId, AudioPlaybackConfiguration.PLAYER_STATE_PAUSED); + mState = AudioPlaybackConfiguration.PLAYER_STATE_PAUSED; + getService().playerEvent(mPlayerIId, mState); } catch (RemoteException e) { Log.e(TAG, "Error talking to audio service, PAUSED state will not be tracked", e); } @@ -161,7 +164,8 @@ public abstract class PlayerBase { void baseStop() { if (DEBUG) { Log.v(TAG, "baseStop() piid=" + mPlayerIId); } try { - getService().playerEvent(mPlayerIId, AudioPlaybackConfiguration.PLAYER_STATE_STOPPED); + mState = AudioPlaybackConfiguration.PLAYER_STATE_STOPPED; + getService().playerEvent(mPlayerIId, mState); } catch (RemoteException e) { Log.e(TAG, "Error talking to audio service, STOPPED state will not be tracked", e); } @@ -193,7 +197,7 @@ public abstract class PlayerBase { * Releases AppOps related resources. */ void baseRelease() { - if (DEBUG) { Log.v(TAG, "baseRelease() piid=" + mPlayerIId); } + if (DEBUG) { Log.v(TAG, "baseRelease() piid=" + mPlayerIId + " state=" + mState); } try { if (mState != AudioPlaybackConfiguration.PLAYER_STATE_RELEASED) { getService().releasePlayer(mPlayerIId); diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java index 6ea51e57ae42..ededf961bb02 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java @@ -209,7 +209,8 @@ class BackgroundTaskLoader implements Runnable { // When svelte, we trim the memory to just the visible thumbnails when // leaving, so don't thrash the cache as the user scrolls (just load // them from scratch each time) - if (config.svelteLevel < RecentsConfiguration.SVELTE_LIMIT_CACHE) { + if (config.svelteLevel < RecentsConfiguration.SVELTE_LIMIT_CACHE + && !ActivityManager.ENABLE_TASK_SNAPSHOTS) { mThumbnailCache.put(t.key, cachedThumbnailData); } } @@ -553,7 +554,9 @@ public class RecentsTaskLoader { // Load the thumbnail from the system thumbnailData = ssp.getTaskThumbnail(taskKey.id); if (thumbnailData.thumbnail != null) { - mThumbnailCache.put(taskKey, thumbnailData); + if (!ActivityManager.ENABLE_TASK_SNAPSHOTS) { + mThumbnailCache.put(taskKey, thumbnailData); + } return thumbnailData.thumbnail; } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 0a088e9124b5..381fe89282c1 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3121,10 +3121,7 @@ public class ConnectivityService extends IConnectivityManager.Stub Settings.Global.TETHER_SUPPORTED, defaultVal) != 0) && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING); return tetherEnabledInSettings && mUserManager.isAdminUser() && - ((mTethering.getTetherableUsbRegexs().length != 0 || - mTethering.getTetherableWifiRegexs().length != 0 || - mTethering.getTetherableBluetoothRegexs().length != 0) && - mTethering.getUpstreamIfaceTypes().length != 0); + mTethering.hasTetherableConfiguration(); } @Override diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index f9b9d6f54669..94acd751c6c4 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -2991,38 +2991,6 @@ class StorageManagerService extends IStorageManager.Stub } } - @Override - public ParcelFileDescriptor mountAppFuse(final String name) throws RemoteException { - try { - final int uid = Binder.getCallingUid(); - final int pid = Binder.getCallingPid(); - final NativeDaemonEvent event = - mConnector.execute("appfuse", "mount", uid, pid, name); - if (event.getFileDescriptors() == null) { - throw new RemoteException("AppFuse FD from vold is null."); - } - return ParcelFileDescriptor.fromFd( - event.getFileDescriptors()[0], - mHandler, - new ParcelFileDescriptor.OnCloseListener() { - @Override - public void onClose(IOException e) { - try { - final NativeDaemonEvent event = mConnector.execute( - "appfuse", "unmount", uid, pid, name); - } catch (NativeDaemonConnectorException unmountException) { - Log.e(TAG, "Failed to unmount appfuse."); - } - } - }); - } catch (NativeDaemonConnectorException e) { - throw e.rethrowAsParcelableException(); - } catch (IOException e) { - throw new RemoteException(e.getMessage()); - } - } - - class CloseableHolder<T extends AutoCloseable> implements AutoCloseable { @Nullable T mCloseable; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index f99dfedb7574..8a0baad3268d 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -9765,15 +9765,17 @@ public class ActivityManagerService extends IActivityManager.Stub enforceCallingPermission(READ_FRAME_BUFFER, "getTaskSnapshot()"); final long ident = Binder.clearCallingIdentity(); try { + final TaskRecord task; synchronized (this) { - final TaskRecord task = mStackSupervisor.anyTaskForIdLocked( + task = mStackSupervisor.anyTaskForIdLocked( taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID); if (task == null) { Slog.w(TAG, "getTaskSnapshot: taskId=" + taskId + " not found"); return null; } - return task.getSnapshot(); } + // Don't call this while holding the lock as this operation might hit the disk. + return task.getSnapshot(); } finally { Binder.restoreCallingIdentity(ident); } diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index e550ac88b0f1..1f5152a1606d 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -583,11 +583,14 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta mWindowContainerController.cancelThumbnailTransition(); } - public TaskSnapshot getSnapshot() { - if (mWindowContainerController == null) { - return null; - } - return mWindowContainerController.getSnapshot(); + /** + * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD! + */ + TaskSnapshot getSnapshot() { + + // TODO: Move this to {@link TaskWindowContainerController} once recent tasks are more + // synchronized between AM and WM. + return mService.mWindowManager.getTaskSnapshot(taskId, userId); } void touchActiveTime() { diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 611b7a83a163..e84bf40b344e 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -76,6 +76,7 @@ import com.android.internal.util.StateMachine; import com.android.server.connectivity.tethering.IControlsTethering; import com.android.server.connectivity.tethering.IPv6TetheringCoordinator; import com.android.server.connectivity.tethering.IPv6TetheringInterfaceServices; +import com.android.server.connectivity.tethering.TetheringConfiguration; import com.android.server.connectivity.tethering.TetherInterfaceStateMachine; import com.android.server.connectivity.tethering.UpstreamNetworkMonitor; import com.android.server.net.BaseNetworkObserver; @@ -118,10 +119,6 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering // used to synchronize public access to members private final Object mPublicSync; - private static final Integer MOBILE_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE); - private static final Integer HIPRI_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_HIPRI); - private static final Integer DUN_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_DUN); - private final INetworkManagementService mNMService; private final INetworkStatsService mStatsService; private final INetworkPolicyManager mPolicyManager; @@ -205,7 +202,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering return (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); } - void updateConfiguration() { + private void updateConfiguration() { mConfig = new TetheringConfiguration(mContext); } @@ -817,6 +814,17 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering return mConfig; } + public boolean hasTetherableConfiguration() { + final TetheringConfiguration cfg = mConfig; + final boolean hasDownstreamConfiguration = + (cfg.tetherableUsbRegexs.length != 0) || + (cfg.tetherableWifiRegexs.length != 0) || + (cfg.tetherableBluetoothRegexs.length != 0); + final boolean hasUpstreamConfiguration = !cfg.preferredUpstreamIfaceTypes.isEmpty(); + + return hasDownstreamConfiguration && hasUpstreamConfiguration; + } + // TODO - update callers to use getTetheringConfiguration(), // which has only final members. public String[] getTetherableUsbRegexs() { @@ -864,17 +872,6 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering return ConnectivityManager.TETHER_ERROR_NO_ERROR; } - public int[] getUpstreamIfaceTypes() { - updateConfiguration(); // TODO - remove? - final Collection<Integer> upstreams = mConfig.preferredUpstreamIfaceTypes; - final int[] values = new int[upstreams.size()]; - int i = 0; - for (Integer u : upstreams) { - values[i++] = u.intValue(); - } - return values; - } - // TODO review API - maybe return ArrayList<String> here and below? public String[] getTetheredIfaces() { ArrayList<String> list = new ArrayList<String>(); @@ -1690,119 +1687,4 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering private static String[] copy(String[] strarray) { return Arrays.copyOf(strarray, strarray.length); } - - private static class TetheringConfiguration { - private static final int DUN_NOT_REQUIRED = 0; - private static final int DUN_REQUIRED = 1; - private static final int DUN_UNSPECIFIED = 2; - - // USB is 192.168.42.1 and 255.255.255.0 - // Wifi is 192.168.43.1 and 255.255.255.0 - // BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1 - // with 255.255.255.0 - // P2P is 192.168.49.1 and 255.255.255.0 - private static final String[] DHCP_DEFAULT_RANGE = { - "192.168.42.2", "192.168.42.254", "192.168.43.2", "192.168.43.254", - "192.168.44.2", "192.168.44.254", "192.168.45.2", "192.168.45.254", - "192.168.46.2", "192.168.46.254", "192.168.47.2", "192.168.47.254", - "192.168.48.2", "192.168.48.254", "192.168.49.2", "192.168.49.254", - }; - - private final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"}; - - public final String[] tetherableUsbRegexs; - public final String[] tetherableWifiRegexs; - public final String[] tetherableBluetoothRegexs; - public final boolean isDunRequired; - public final Collection<Integer> preferredUpstreamIfaceTypes; - public final String[] dhcpRanges; - public final String[] defaultIPv4DNS; - - public TetheringConfiguration(Context ctx) { - tetherableUsbRegexs = ctx.getResources().getStringArray( - com.android.internal.R.array.config_tether_usb_regexs); - tetherableWifiRegexs = ctx.getResources().getStringArray( - com.android.internal.R.array.config_tether_wifi_regexs); - tetherableBluetoothRegexs = ctx.getResources().getStringArray( - com.android.internal.R.array.config_tether_bluetooth_regexs); - - isDunRequired = checkDunRequired(ctx); - preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, isDunRequired); - - dhcpRanges = getDhcpRanges(ctx); - defaultIPv4DNS = copy(DEFAULT_IPV4_DNS); - } - - public boolean isUsb(String iface) { - for (String regex : tetherableUsbRegexs) { - if (iface.matches(regex)) return true; - } - return false; - } - - public boolean isWifi(String iface) { - for (String regex : tetherableWifiRegexs) { - if (iface.matches(regex)) return true; - } - return false; - } - - public boolean isBluetooth(String iface) { - for (String regex : tetherableBluetoothRegexs) { - if (iface.matches(regex)) return true; - } - return false; - } - - private static boolean checkDunRequired(Context ctx) { - final TelephonyManager tm = ctx.getSystemService(TelephonyManager.class); - final int secureSetting = - (tm != null) ? tm.getTetherApnRequired() : DUN_UNSPECIFIED; - return (secureSetting == DUN_REQUIRED); - } - - private static Collection<Integer> getUpstreamIfaceTypes(Context ctx, boolean requiresDun) { - final int ifaceTypes[] = ctx.getResources().getIntArray( - com.android.internal.R.array.config_tether_upstream_types); - final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length); - for (int i : ifaceTypes) { - upstreamIfaceTypes.add(i); - } - - // Fix up upstream interface types for DUN or mobile. - // TODO: Perform this filtering step in the above for loop. - if (requiresDun) { - while (upstreamIfaceTypes.contains(MOBILE_TYPE)) { - upstreamIfaceTypes.remove(MOBILE_TYPE); - } - while (upstreamIfaceTypes.contains(HIPRI_TYPE)) { - upstreamIfaceTypes.remove(HIPRI_TYPE); - } - if (!upstreamIfaceTypes.contains(DUN_TYPE)) { - upstreamIfaceTypes.add(DUN_TYPE); - } - } else { - while (upstreamIfaceTypes.contains(DUN_TYPE)) { - upstreamIfaceTypes.remove(DUN_TYPE); - } - if (!upstreamIfaceTypes.contains(MOBILE_TYPE)) { - upstreamIfaceTypes.add(MOBILE_TYPE); - } - if (!upstreamIfaceTypes.contains(HIPRI_TYPE)) { - upstreamIfaceTypes.add(HIPRI_TYPE); - } - } - - return upstreamIfaceTypes; - } - - private static String[] getDhcpRanges(Context ctx) { - final String[] fromResource = ctx.getResources().getStringArray( - com.android.internal.R.array.config_tether_dhcp_range); - if ((fromResource.length > 0) && (fromResource.length % 2 == 0)) { - return fromResource; - } - return copy(DHCP_DEFAULT_RANGE); - } - } } diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java new file mode 100644 index 000000000000..14d06cc755ef --- /dev/null +++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java @@ -0,0 +1,163 @@ +/* + * 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 com.android.server.connectivity.tethering; + +import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; +import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; + +import android.content.Context; +import android.content.res.Resources; +import android.telephony.TelephonyManager; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + + +/** + * A utility class to encapsulate the various tethering configuration elements. + * + * This configuration data includes elements describing upstream properties + * (preferred and required types of upstream connectivity as well as default + * DNS servers to use if none are available) and downstream properties (such + * as regular expressions use to match suitable downstream interfaces and the + * DHCPv4 ranges to use). + * + * @hide + */ +public class TetheringConfiguration { + private static final String TAG = TetheringConfiguration.class.getSimpleName(); + + private static final int DUN_NOT_REQUIRED = 0; + private static final int DUN_REQUIRED = 1; + private static final int DUN_UNSPECIFIED = 2; + + // USB is 192.168.42.1 and 255.255.255.0 + // Wifi is 192.168.43.1 and 255.255.255.0 + // BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1 + // with 255.255.255.0 + // P2P is 192.168.49.1 and 255.255.255.0 + private static final String[] DHCP_DEFAULT_RANGE = { + "192.168.42.2", "192.168.42.254", "192.168.43.2", "192.168.43.254", + "192.168.44.2", "192.168.44.254", "192.168.45.2", "192.168.45.254", + "192.168.46.2", "192.168.46.254", "192.168.47.2", "192.168.47.254", + "192.168.48.2", "192.168.48.254", "192.168.49.2", "192.168.49.254", + }; + + private final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"}; + + public final String[] tetherableUsbRegexs; + public final String[] tetherableWifiRegexs; + public final String[] tetherableBluetoothRegexs; + public final boolean isDunRequired; + public final Collection<Integer> preferredUpstreamIfaceTypes; + public final String[] dhcpRanges; + public final String[] defaultIPv4DNS; + + public TetheringConfiguration(Context ctx) { + tetherableUsbRegexs = ctx.getResources().getStringArray( + com.android.internal.R.array.config_tether_usb_regexs); + tetherableWifiRegexs = ctx.getResources().getStringArray( + com.android.internal.R.array.config_tether_wifi_regexs); + tetherableBluetoothRegexs = ctx.getResources().getStringArray( + com.android.internal.R.array.config_tether_bluetooth_regexs); + + isDunRequired = checkDunRequired(ctx); + preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, isDunRequired); + + dhcpRanges = getDhcpRanges(ctx); + defaultIPv4DNS = copy(DEFAULT_IPV4_DNS); + } + + public boolean isUsb(String iface) { + return matchesDownstreamRegexs(iface, tetherableUsbRegexs); + } + + public boolean isWifi(String iface) { + return matchesDownstreamRegexs(iface, tetherableWifiRegexs); + } + + public boolean isBluetooth(String iface) { + return matchesDownstreamRegexs(iface, tetherableBluetoothRegexs); + } + + private static boolean checkDunRequired(Context ctx) { + final TelephonyManager tm = ctx.getSystemService(TelephonyManager.class); + final int secureSetting = + (tm != null) ? tm.getTetherApnRequired() : DUN_UNSPECIFIED; + return (secureSetting == DUN_REQUIRED); + } + + private static Collection<Integer> getUpstreamIfaceTypes(Context ctx, boolean requiresDun) { + final int ifaceTypes[] = ctx.getResources().getIntArray( + com.android.internal.R.array.config_tether_upstream_types); + final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length); + for (int i : ifaceTypes) { + switch (i) { + case TYPE_MOBILE: + case TYPE_MOBILE_HIPRI: + if (requiresDun) continue; + break; + case TYPE_MOBILE_DUN: + if (!requiresDun) continue; + break; + } + upstreamIfaceTypes.add(i); + } + + // Fix up upstream interface types for DUN or mobile. NOTE: independent + // of the value of |requiresDun|, cell data of one form or another is + // *always* an upstream, regardless of the upstream interface types + // specified by configuration resources. + if (requiresDun) { + if (!upstreamIfaceTypes.contains(TYPE_MOBILE_DUN)) { + upstreamIfaceTypes.add(TYPE_MOBILE_DUN); + } + } else { + if (!upstreamIfaceTypes.contains(TYPE_MOBILE)) { + upstreamIfaceTypes.add(TYPE_MOBILE); + } + if (!upstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)) { + upstreamIfaceTypes.add(TYPE_MOBILE_HIPRI); + } + } + + return upstreamIfaceTypes; + } + + private static boolean matchesDownstreamRegexs(String iface, String[] regexs) { + for (String regex : regexs) { + if (iface.matches(regex)) return true; + } + return false; + } + + private static String[] getDhcpRanges(Context ctx) { + final String[] fromResource = ctx.getResources().getStringArray( + com.android.internal.R.array.config_tether_dhcp_range); + if ((fromResource.length > 0) && (fromResource.length % 2 == 0)) { + return fromResource; + } + return copy(DHCP_DEFAULT_RANGE); + } + + private static String[] copy(String[] strarray) { + return Arrays.copyOf(strarray, strarray.length); + } +} 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/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java index 34f675226a3b..0436139f4fda 100644 --- a/services/core/java/com/android/server/wm/AppWindowContainerController.java +++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java @@ -492,7 +492,7 @@ public class AppWindowContainerController private boolean createSnapshot() { final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot( - mContainer.mTask); + mContainer.mTask.mTaskId, mContainer.mTask.mUserId, false /* restoreFromDisk */); if (snapshot == null) { return false; diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 505051fcb9d2..3958510f5957 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2259,10 +2259,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } // Don't include wallpaper in bounds calculation - if (includeDecor && !stackBounds.isEmpty()) { - frame.set(stackBounds); - } else if (includeDecor) { - mutableIncludeFullDisplay.value = true; + if (!mutableIncludeFullDisplay.value && includeDecor) { + final TaskStack stack = w.getStack(); + if (stack != null) { + stack.getBounds(frame); + } } else if (!mutableIncludeFullDisplay.value && !w.mIsWallpaper) { final Rect wf = w.mFrame; final Rect cr = w.mContentInsets; diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java index c86229b1e477..601bf28b7ed8 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotCache.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java @@ -19,8 +19,11 @@ package com.android.server.wm; import android.annotation.Nullable; import android.app.ActivityManager.TaskSnapshot; import android.util.ArrayMap; +import android.util.LruCache; import java.io.PrintWriter; +import java.util.Map; +import java.util.Map.Entry; /** * Caches snapshots. See {@link TaskSnapshotController}. @@ -29,51 +32,125 @@ import java.io.PrintWriter; */ class TaskSnapshotCache { - private final ArrayMap<AppWindowToken, Task> mAppTaskMap = new ArrayMap<>(); - private final ArrayMap<Task, CacheEntry> mCache = new ArrayMap<>(); + // TODO: Make this more dynamic to accomodate for different clients. + private static final int RETRIEVAL_CACHE_SIZE = 4; + + private final WindowManagerService mService; + private final TaskSnapshotLoader mLoader; + private final ArrayMap<AppWindowToken, Integer> mAppTaskMap = new ArrayMap<>(); + private final ArrayMap<Integer, CacheEntry> mRunningCache = new ArrayMap<>(); + private final LruCache<Integer, TaskSnapshot> mRetrievalCache = + new LruCache<>(RETRIEVAL_CACHE_SIZE); + + TaskSnapshotCache(WindowManagerService service, TaskSnapshotLoader loader) { + mService = service; + mLoader = loader; + } void putSnapshot(Task task, TaskSnapshot snapshot) { - final CacheEntry entry = mCache.get(task); + final CacheEntry entry = mRunningCache.get(task.mTaskId); if (entry != null) { mAppTaskMap.remove(entry.topApp); } final AppWindowToken top = task.getTopChild(); - mAppTaskMap.put(top, task); - mCache.put(task, new CacheEntry(snapshot, task.getTopChild())); + mAppTaskMap.put(top, task.mTaskId); + mRunningCache.put(task.mTaskId, new CacheEntry(snapshot, task.getTopChild())); + mRetrievalCache.put(task.mTaskId, snapshot); } - @Nullable TaskSnapshot getSnapshot(Task task) { - final CacheEntry entry = mCache.get(task); - return entry != null ? entry.snapshot : null; + /** + * If {@param restoreFromDisk} equals {@code true}, DO NOT HOLD THE WINDOW MANAGER LOCK! + */ + @Nullable TaskSnapshot getSnapshot(int taskId, int userId, boolean restoreFromDisk) { + + synchronized (mService.mWindowMap) { + // Try the running cache. + final CacheEntry entry = mRunningCache.get(taskId); + if (entry != null) { + return entry.snapshot; + } + + // Try the retrieval cache. + final TaskSnapshot snapshot = mRetrievalCache.get(taskId); + if (snapshot != null) { + return snapshot; + } + } + + // Try to restore from disk if asked. + if (!restoreFromDisk) { + return null; + } + return tryRestoreFromDisk(taskId, userId); } /** - * Cleans the cache after an app window token's process died. + * DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING THIS METHOD! */ - void cleanCache(AppWindowToken wtoken) { - final Task task = mAppTaskMap.get(wtoken); - if (task != null) { - removeEntry(task); + private TaskSnapshot tryRestoreFromDisk(int taskId, int userId) { + final TaskSnapshot snapshot = mLoader.loadTask(taskId, userId); + if (snapshot == null) { + return null; } + synchronized (mService.mWindowMap) { + mRetrievalCache.put(taskId, snapshot); + } + return snapshot; } - private void removeEntry(Task task) { - final CacheEntry entry = mCache.get(task); + /** + * Called when an app token has been removed + */ + void onAppRemoved(AppWindowToken wtoken) { + final Integer taskId = mAppTaskMap.get(wtoken); + if (taskId != null) { + removeRunningEntry(taskId); + } + if (wtoken.mTask != null) { + mRetrievalCache.remove(wtoken.mTask.mTaskId); + } + } + + /** + * Callend when an app window token's process died. + */ + void onAppDied(AppWindowToken wtoken) { + final Integer taskId = mAppTaskMap.get(wtoken); + if (taskId != null) { + removeRunningEntry(taskId); + } + } + + void onTaskRemoved(int taskId) { + removeRunningEntry(taskId); + mRetrievalCache.remove(taskId); + } + + private void removeRunningEntry(int taskId) { + final CacheEntry entry = mRunningCache.get(taskId); if (entry != null) { mAppTaskMap.remove(entry.topApp); - mCache.remove(task); + mRunningCache.remove(taskId); } } void dump(PrintWriter pw, String prefix) { final String doublePrefix = prefix + " "; final String triplePrefix = doublePrefix + " "; + final String quadruplePrefix = triplePrefix + " "; pw.println(prefix + "SnapshotCache"); - for (int i = mCache.size() - 1; i >= 0; i--) { - final CacheEntry entry = mCache.valueAt(i); - pw.println(doublePrefix + "Entry taskId=" + mCache.keyAt(i).mTaskId); - pw.println(triplePrefix + "topApp=" + entry.topApp); - pw.println(triplePrefix + "snapshot=" + entry.snapshot); + pw.println(doublePrefix + "RunningCache"); + for (int i = mRunningCache.size() - 1; i >= 0; i--) { + final CacheEntry entry = mRunningCache.valueAt(i); + pw.println(triplePrefix + "Entry taskId=" + mRunningCache.keyAt(i)); + pw.println(quadruplePrefix + "topApp=" + entry.topApp); + pw.println(quadruplePrefix + "snapshot=" + entry.snapshot); + } + pw.println(doublePrefix + "RetrievalCache"); + final Map<Integer, TaskSnapshot> retrievalSnapshot = mRetrievalCache.snapshot(); + for (Entry<Integer, TaskSnapshot> entry : retrievalSnapshot.entrySet()) { + pw.println(triplePrefix + "Entry taskId=" + entry.getKey()); + pw.println(quadruplePrefix + "snapshot=" + entry.getValue()); } } diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 10ecf3bb1ae3..15878f6e414a 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -28,7 +28,6 @@ import android.view.WindowManagerPolicy.StartingSurface; import com.android.internal.annotations.VisibleForTesting; -import java.io.File; import java.io.PrintWriter; /** @@ -48,7 +47,7 @@ class TaskSnapshotController { private final WindowManagerService mService; - private final TaskSnapshotCache mCache = new TaskSnapshotCache(); + private final TaskSnapshotCache mCache; private final TaskSnapshotPersister mPersister = new TaskSnapshotPersister( Environment::getDataSystemCeDirectory); private final TaskSnapshotLoader mLoader = new TaskSnapshotLoader(mPersister); @@ -56,6 +55,7 @@ class TaskSnapshotController { TaskSnapshotController(WindowManagerService service) { mService = service; + mCache = new TaskSnapshotCache(mService, mLoader); } void systemReady() { @@ -86,8 +86,12 @@ class TaskSnapshotController { } } - @Nullable TaskSnapshot getSnapshot(Task task) { - return mCache.getSnapshot(task); + /** + * Retrieves a snapshot. If {@param restoreFromDisk} equals {@code true}, DO HOLD THE WINDOW + * MANAGER LOCK WHEN CALLING THIS METHOD! + */ + @Nullable TaskSnapshot getSnapshot(int taskId, int userId, boolean restoreFromDisk) { + return mCache.getSnapshot(taskId, userId, restoreFromDisk); } /** @@ -138,20 +142,18 @@ class TaskSnapshotController { * Called when an {@link AppWindowToken} has been removed. */ void onAppRemoved(AppWindowToken wtoken) { - // TODO: Clean from both recents and running cache. - mCache.cleanCache(wtoken); + mCache.onAppRemoved(wtoken); } /** * Called when the process of an {@link AppWindowToken} has died. */ void onAppDied(AppWindowToken wtoken) { - - // TODO: Only clean from running cache. - mCache.cleanCache(wtoken); + mCache.onAppDied(wtoken); } void notifyTaskRemovedFromRecents(int taskId, int userId) { + mCache.onTaskRemoved(taskId); mPersister.onTaskRemovedFromRecents(taskId, userId); } diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java index 96b79a6e19a2..3c438ca3195f 100644 --- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java +++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java @@ -263,19 +263,6 @@ public class TaskWindowContainerController } } - /** - * @return a graphic buffer representing a screenshot of a task - */ - public TaskSnapshot getSnapshot() { - synchronized (mWindowMap) { - if (mContainer == null) { - Slog.w(TAG_WM, "getSnapshot: taskId " + mTaskId + " not found."); - return null; - } - return mService.mTaskSnapshotController.getSnapshot(mContainer); - } - } - void reportSnapshotChanged(TaskSnapshot snapshot) { mHandler.obtainMessage(REPORT_SNAPSHOT_CHANGED, snapshot).sendToTarget(); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 9a6cd2cb41f8..c8f4bd23204d 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -97,6 +97,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityManagerInternal; import android.app.AppOpsManager; import android.app.IActivityManager; @@ -3902,6 +3903,10 @@ public class WindowManagerService extends IWindowManager.Stub return true; } + public TaskSnapshot getTaskSnapshot(int taskId, int userId) { + return mTaskSnapshotController.getSnapshot(taskId, userId, true /* restoreFromDisk */); + } + /** * In case a task write/delete operation was lost because the system crashed, this makes sure to * clean up the directory to remove obsolete files. 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/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java index 48d4770c2046..e1a22d9a9486 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE; import static android.graphics.GraphicBuffer.USAGE_SW_READ_NEVER; +import static android.graphics.GraphicBuffer.USAGE_SW_READ_RARELY; import static android.graphics.GraphicBuffer.USAGE_SW_WRITE_NEVER; import static android.graphics.GraphicBuffer.create; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; @@ -26,13 +27,18 @@ import static junit.framework.Assert.assertNull; import android.app.ActivityManager.TaskSnapshot; import android.content.res.Configuration; +import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.GraphicBuffer; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.os.Debug; import android.platform.test.annotations.Presubmit; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -44,21 +50,75 @@ import org.junit.runner.RunWith; @SmallTest @Presubmit @RunWith(AndroidJUnit4.class) -public class TaskSnapshotCacheTest extends WindowTestsBase { +public class TaskSnapshotCacheTest extends TaskSnapshotPersisterTestBase { + + private TaskSnapshotCache mCache; + + @Before + public void setUp() throws Exception { + super.setUp(); + mCache = new TaskSnapshotCache(sWm, mLoader); + } + + @Test + public void testAppRemoved() throws Exception { + final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window"); + mCache.putSnapshot(window.getTask(), createSnapshot()); + assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */, + false /* restoreFromDisk */)); + mCache.onAppRemoved(window.mAppToken); + assertNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */, + false /* restoreFromDisk */)); + } + + @Test + public void testAppDied() throws Exception { + final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window"); + mCache.putSnapshot(window.getTask(), createSnapshot()); + assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */, + false /* restoreFromDisk */)); + mCache.onAppDied(window.mAppToken); + + // Should still be in the retrieval cache. + assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */, + false /* restoreFromDisk */)); + + // Trash retrieval cache. + for (int i = 0; i < 20; i++) { + mCache.putSnapshot(createWindow(null, FIRST_APPLICATION_WINDOW, "window").getTask(), + createSnapshot()); + } + + // Should not be in cache anymore + assertNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */, + false /* restoreFromDisk */)); + } @Test - public void testCleanCache() throws Exception { - TaskSnapshotCache snapshotCache = new TaskSnapshotCache(); + public void testTaskRemoved() throws Exception { final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window"); - snapshotCache.putSnapshot(window.getTask(), createSnapshot()); - assertNotNull(snapshotCache.getSnapshot(window.getTask())); - snapshotCache.cleanCache(window.mAppToken); - assertNull(snapshotCache.getSnapshot(window.getTask())); + mCache.putSnapshot(window.getTask(), createSnapshot()); + assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */, + false /* restoreFromDisk */)); + mCache.onTaskRemoved(window.getTask().mTaskId); + assertNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */, + false /* restoreFromDisk */)); } - private TaskSnapshot createSnapshot() { - GraphicBuffer buffer = create(1, 1, PixelFormat.RGBA_8888, - USAGE_HW_TEXTURE | USAGE_SW_WRITE_NEVER | USAGE_SW_READ_NEVER); - return new TaskSnapshot(buffer, Configuration.ORIENTATION_PORTRAIT, new Rect()); + @Test + public void testRestoreFromDisk() throws Exception { + final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window"); + mPersister.persistSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId, createSnapshot()); + mPersister.waitForQueueEmpty(); + assertNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId, + false /* restoreFromDisk */)); + + // Load it from disk + assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId, + true /* restoreFromDisk */)); + + // Make sure it's in the cache now. + assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId, + false /* restoreFromDisk */)); } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java index 8d6d2daeb6a2..dc008b52c3b3 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java @@ -16,8 +16,6 @@ package com.android.server.wm; -import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE; -import static android.graphics.GraphicBuffer.USAGE_SW_READ_RARELY; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -25,18 +23,11 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.app.ActivityManager.TaskSnapshot; -import android.content.pm.UserInfo; import android.content.res.Configuration; import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.GraphicBuffer; -import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.SystemClock; -import android.os.UserManager; import android.platform.test.annotations.Presubmit; -import android.support.test.InstrumentationRegistry; import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; import android.util.ArraySet; @@ -44,11 +35,6 @@ import android.util.ArraySet; import com.android.internal.util.Predicate; import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; @@ -62,42 +48,11 @@ import java.io.File; @MediumTest @Presubmit @RunWith(AndroidJUnit4.class) -public class TaskSnapshotPersisterLoaderTest { +public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBase { private static final String TEST_USER_NAME = "TaskSnapshotPersisterTest User"; private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40); - private TaskSnapshotPersister mPersister; - private TaskSnapshotLoader mLoader; - private static int sTestUserId; - private static File sFilesDir; - private static UserManager sUserManager; - - @BeforeClass - public static void setUpUser() { - sUserManager = UserManager.get(InstrumentationRegistry.getContext()); - sTestUserId = createUser(TEST_USER_NAME, 0); - sFilesDir = InstrumentationRegistry.getContext().getFilesDir(); - } - - @AfterClass - public static void tearDownUser() { - removeUser(sTestUserId); - } - - @Before - public void setUp() throws Exception { - mPersister = new TaskSnapshotPersister( - userId -> sFilesDir); - mLoader = new TaskSnapshotLoader(mPersister); - mPersister.start(); - } - - @After - public void tearDown() throws Exception { - cleanDirectory(); - } - @Test public void testPersistAndLoadSnapshot() { mPersister.persistSnapshot(1 , sTestUserId, createSnapshot()); @@ -188,35 +143,4 @@ public class TaskSnapshotPersisterLoaderTest { new File(sFilesDir.getPath() + "/snapshots/2.png") }; assertTrueForFiles(existsFiles, File::exists, " must exist"); } - - private TaskSnapshot createSnapshot() { - GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888, - USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY); - Canvas c = buffer.lockCanvas(); - c.drawColor(Color.RED); - buffer.unlockCanvasAndPost(c); - return new TaskSnapshot(buffer, Configuration.ORIENTATION_PORTRAIT, TEST_INSETS); - } - - private static int createUser(String name, int flags) { - UserInfo user = sUserManager.createUser(name, flags); - if (user == null) { - Assert.fail("Error while creating the test user: " + TEST_USER_NAME); - } - return user.id; - } - - private static void removeUser(int userId) { - if (!sUserManager.removeUser(userId)) { - Assert.fail("Error while removing the test user: " + TEST_USER_NAME); - } - } - - private void cleanDirectory() { - for (File file : new File(sFilesDir, "snapshots").listFiles()) { - if (!file.isDirectory()) { - file.delete(); - } - } - } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java new file mode 100644 index 000000000000..6fc6edb0812b --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java @@ -0,0 +1,111 @@ +/* + * 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 com.android.server.wm; + +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; +import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE; +import static android.graphics.GraphicBuffer.USAGE_SW_READ_RARELY; + +import android.app.ActivityManager.TaskSnapshot; +import android.content.pm.UserInfo; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.GraphicBuffer; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.os.UserManager; +import android.support.test.InstrumentationRegistry; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; + +import java.io.File; + +/** + * Base class for tests that use a {@link TaskSnapshotPersister}. + */ +class TaskSnapshotPersisterTestBase extends WindowTestsBase { + + private static final String TEST_USER_NAME = "TaskSnapshotPersisterTest User"; + private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40); + + TaskSnapshotPersister mPersister; + TaskSnapshotLoader mLoader; + static int sTestUserId; + static File sFilesDir; + private static UserManager sUserManager; + + @BeforeClass + public static void setUpUser() { + sUserManager = UserManager.get(InstrumentationRegistry.getContext()); + sTestUserId = createUser(TEST_USER_NAME, 0); + sFilesDir = InstrumentationRegistry.getContext().getFilesDir(); + } + + @AfterClass + public static void tearDownUser() { + removeUser(sTestUserId); + } + + @Before + public void setUp() throws Exception { + super.setUp(); + mPersister = new TaskSnapshotPersister( + userId -> sFilesDir); + mLoader = new TaskSnapshotLoader(mPersister); + mPersister.start(); + } + + @After + public void tearDown() throws Exception { + cleanDirectory(); + } + + private static int createUser(String name, int flags) { + UserInfo user = sUserManager.createUser(name, flags); + if (user == null) { + Assert.fail("Error while creating the test user: " + TEST_USER_NAME); + } + return user.id; + } + + private static void removeUser(int userId) { + if (!sUserManager.removeUser(userId)) { + Assert.fail("Error while removing the test user: " + TEST_USER_NAME); + } + } + + private void cleanDirectory() { + for (File file : new File(sFilesDir, "snapshots").listFiles()) { + if (!file.isDirectory()) { + file.delete(); + } + } + } + + TaskSnapshot createSnapshot() { + GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888, + USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY); + Canvas c = buffer.lockCanvas(); + c.drawColor(Color.RED); + buffer.unlockCanvasAndPost(c); + return new TaskSnapshot(buffer, ORIENTATION_PORTRAIT, TEST_INSETS); + } +} 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/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java index 0cd065169713..1e67769277da 100644 --- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java @@ -117,10 +117,7 @@ public class UpstreamNetworkMonitorTest { mUNM.registerMobileNetworkRequest(); assertTrue(mUNM.mobileNetworkRequested()); - assertEquals(1, mCM.requested.size()); - assertEquals(1, mCM.legacyTypeMap.size()); - assertEquals(Integer.valueOf(TYPE_MOBILE_HIPRI), - mCM.legacyTypeMap.values().iterator().next()); + assertUpstreamTypeRequested(TYPE_MOBILE_HIPRI); assertFalse(mCM.isDunRequested()); mUNM.stop(); @@ -143,10 +140,7 @@ public class UpstreamNetworkMonitorTest { mUNM.registerMobileNetworkRequest(); assertTrue(mUNM.mobileNetworkRequested()); - assertEquals(1, mCM.requested.size()); - assertEquals(1, mCM.legacyTypeMap.size()); - assertEquals(Integer.valueOf(TYPE_MOBILE_DUN), - mCM.legacyTypeMap.values().iterator().next()); + assertUpstreamTypeRequested(TYPE_MOBILE_DUN); assertTrue(mCM.isDunRequested()); mUNM.stop(); @@ -154,6 +148,38 @@ public class UpstreamNetworkMonitorTest { assertTrue(mCM.hasNoCallbacks()); } + @Test + public void testUpdateMobileRequiredDun() throws Exception { + mUNM.start(); + + // Test going from no-DUN to DUN correctly re-registers callbacks. + mUNM.updateMobileRequiresDun(false); + mUNM.registerMobileNetworkRequest(); + assertTrue(mUNM.mobileNetworkRequested()); + assertUpstreamTypeRequested(TYPE_MOBILE_HIPRI); + assertFalse(mCM.isDunRequested()); + mUNM.updateMobileRequiresDun(true); + assertTrue(mUNM.mobileNetworkRequested()); + assertUpstreamTypeRequested(TYPE_MOBILE_DUN); + assertTrue(mCM.isDunRequested()); + + // Test going from DUN to no-DUN correctly re-registers callbacks. + mUNM.updateMobileRequiresDun(false); + assertTrue(mUNM.mobileNetworkRequested()); + assertUpstreamTypeRequested(TYPE_MOBILE_HIPRI); + assertFalse(mCM.isDunRequested()); + + mUNM.stop(); + assertFalse(mUNM.mobileNetworkRequested()); + } + + private void assertUpstreamTypeRequested(int upstreamType) throws Exception { + assertEquals(1, mCM.requested.size()); + assertEquals(1, mCM.legacyTypeMap.size()); + assertEquals(Integer.valueOf(upstreamType), + mCM.legacyTypeMap.values().iterator().next()); + } + private static class TestConnectivityManager extends ConnectivityManager { public Set<NetworkCallback> trackingDefault = new HashSet<>(); public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>(); diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index 75a316092a02..045d68c3bbae 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -211,7 +211,7 @@ private: bool isValidResourceType(const String8& type) { return type == "anim" || type == "animator" || type == "interpolator" - || type == "transition" + || type == "transition" || type == "font" || type == "drawable" || type == "layout" || type == "values" || type == "xml" || type == "raw" || type == "color" || type == "menu" || type == "mipmap"; 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]; } |