diff options
Diffstat (limited to 'android/content')
-rw-r--r-- | android/content/ContentResolver.java | 84 | ||||
-rw-r--r-- | android/content/Context.java | 2 | ||||
-rw-r--r-- | android/content/Intent.java | 42 | ||||
-rw-r--r-- | android/content/QuickViewConstants.java | 4 | ||||
-rw-r--r-- | android/content/pm/ApplicationInfo.java | 102 | ||||
-rw-r--r-- | android/content/pm/LauncherApps.java | 24 | ||||
-rw-r--r-- | android/content/pm/PackageInfo.java | 55 | ||||
-rw-r--r-- | android/content/pm/PackageManager.java | 89 | ||||
-rw-r--r-- | android/content/pm/PackageManagerInternal.java | 38 | ||||
-rw-r--r-- | android/content/pm/PackageParser.java | 24 | ||||
-rw-r--r-- | android/content/pm/PackageSharedLibraryUpdater.java | 2 | ||||
-rw-r--r-- | android/content/pm/PackageUserState.java | 6 | ||||
-rw-r--r-- | android/content/pm/SigningInfo.java | 139 |
13 files changed, 426 insertions, 185 deletions
diff --git a/android/content/ContentResolver.java b/android/content/ContentResolver.java index 9f3df377..f7908b69 100644 --- a/android/content/ContentResolver.java +++ b/android/content/ContentResolver.java @@ -51,7 +51,6 @@ import android.text.TextUtils; import android.util.EventLog; import android.util.Log; -import com.android.internal.util.ArrayUtils; import com.android.internal.util.MimeIconUtils; import com.android.internal.util.Preconditions; @@ -602,6 +601,8 @@ public abstract class ContentResolver { try { return provider.getType(url); } catch (RemoteException e) { + // Arbitrary and not worth documenting, as Activity + // Manager will kill this process shortly anyway. return null; } catch (java.lang.Exception e) { Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")"); @@ -620,9 +621,7 @@ public abstract class ContentResolver { ContentProvider.getUriWithoutUserId(url), resolveUserId(url)); return type; } catch (RemoteException e) { - // Arbitrary and not worth documenting, as Activity - // Manager will kill this process shortly anyway. - return null; + throw e.rethrowFromSystemServer(); } catch (java.lang.Exception e) { Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")"); return null; @@ -1964,6 +1963,7 @@ public abstract class ContentResolver { getContentService().registerContentObserver(uri, notifyForDescendents, observer.getContentObserver(), userHandle, mTargetSdkVersion); } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -1982,6 +1982,7 @@ public abstract class ContentResolver { contentObserver); } } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -2089,6 +2090,7 @@ public abstract class ContentResolver { syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0, userHandle, mTargetSdkVersion); } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -2105,6 +2107,7 @@ public abstract class ContentResolver { observer != null && observer.deliverSelfNotifications(), flags, userHandle, mTargetSdkVersion); } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -2126,6 +2129,7 @@ public abstract class ContentResolver { ContentProvider.getUriWithoutUserId(uri), modeFlags, /* toPackage= */ null, resolveUserId(uri)); } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -2141,6 +2145,7 @@ public abstract class ContentResolver { ContentProvider.getUriWithoutUserId(uri), modeFlags, toPackage, resolveUserId(uri)); } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -2160,6 +2165,7 @@ public abstract class ContentResolver { ContentProvider.getUriWithoutUserId(uri), modeFlags, /* toPackage= */ null, resolveUserId(uri)); } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -2178,7 +2184,7 @@ public abstract class ContentResolver { return ActivityManager.getService() .getPersistedUriPermissions(mPackageName, true).getList(); } catch (RemoteException e) { - throw new RuntimeException("Activity manager has died", e); + throw e.rethrowFromSystemServer(); } } @@ -2194,7 +2200,7 @@ public abstract class ContentResolver { return ActivityManager.getService() .getPersistedUriPermissions(mPackageName, false).getList(); } catch (RemoteException e) { - throw new RuntimeException("Activity manager has died", e); + throw e.rethrowFromSystemServer(); } } @@ -2273,7 +2279,7 @@ public abstract class ContentResolver { try { getContentService().syncAsUser(request, userId); } catch(RemoteException e) { - // Shouldn't happen. + throw e.rethrowFromSystemServer(); } } @@ -2285,7 +2291,7 @@ public abstract class ContentResolver { try { getContentService().sync(request); } catch(RemoteException e) { - // Shouldn't happen. + throw e.rethrowFromSystemServer(); } } @@ -2349,6 +2355,7 @@ public abstract class ContentResolver { try { getContentService().cancelSync(account, authority, null); } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -2360,6 +2367,7 @@ public abstract class ContentResolver { try { getContentService().cancelSyncAsUser(account, authority, null, userId); } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -2371,7 +2379,7 @@ public abstract class ContentResolver { try { return getContentService().getSyncAdapterTypes(); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2383,7 +2391,7 @@ public abstract class ContentResolver { try { return getContentService().getSyncAdapterTypesAsUser(userId); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2397,8 +2405,8 @@ public abstract class ContentResolver { try { return getContentService().getSyncAdapterPackagesForAuthorityAsUser(authority, userId); } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } - return ArrayUtils.emptyArray(String.class); } /** @@ -2414,7 +2422,7 @@ public abstract class ContentResolver { try { return getContentService().getSyncAutomatically(account, authority); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2427,7 +2435,7 @@ public abstract class ContentResolver { try { return getContentService().getSyncAutomaticallyAsUser(account, authority, userId); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2453,8 +2461,7 @@ public abstract class ContentResolver { try { getContentService().setSyncAutomaticallyAsUser(account, authority, sync, userId); } catch (RemoteException e) { - // exception ignored; if this is thrown then it means the runtime is in the midst of - // being restarted + throw e.rethrowFromSystemServer(); } } @@ -2500,8 +2507,7 @@ public abstract class ContentResolver { try { getContentService().addPeriodicSync(account, authority, extras, pollFrequency); } catch (RemoteException e) { - // exception ignored; if this is thrown then it means the runtime is in the midst of - // being restarted + throw e.rethrowFromSystemServer(); } } @@ -2540,7 +2546,7 @@ public abstract class ContentResolver { try { getContentService().removePeriodicSync(account, authority, extras); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2564,8 +2570,7 @@ public abstract class ContentResolver { try { getContentService().cancelRequest(request); } catch (RemoteException e) { - // exception ignored; if this is thrown then it means the runtime is in the midst of - // being restarted + throw e.rethrowFromSystemServer(); } } @@ -2582,7 +2587,7 @@ public abstract class ContentResolver { try { return getContentService().getPeriodicSyncs(account, authority, null); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2596,7 +2601,7 @@ public abstract class ContentResolver { try { return getContentService().getIsSyncable(account, authority); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2609,7 +2614,7 @@ public abstract class ContentResolver { try { return getContentService().getIsSyncableAsUser(account, authority, userId); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2623,8 +2628,7 @@ public abstract class ContentResolver { try { getContentService().setIsSyncable(account, authority, syncable); } catch (RemoteException e) { - // exception ignored; if this is thrown then it means the runtime is in the midst of - // being restarted + throw e.rethrowFromSystemServer(); } } @@ -2640,7 +2644,7 @@ public abstract class ContentResolver { try { return getContentService().getMasterSyncAutomatically(); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2652,7 +2656,7 @@ public abstract class ContentResolver { try { return getContentService().getMasterSyncAutomaticallyAsUser(userId); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2676,8 +2680,7 @@ public abstract class ContentResolver { try { getContentService().setMasterSyncAutomaticallyAsUser(sync, userId); } catch (RemoteException e) { - // exception ignored; if this is thrown then it means the runtime is in the midst of - // being restarted + throw e.rethrowFromSystemServer(); } } @@ -2701,7 +2704,7 @@ public abstract class ContentResolver { try { return getContentService().isSyncActive(account, authority, null); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2727,7 +2730,7 @@ public abstract class ContentResolver { } return syncs.get(0); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2744,7 +2747,7 @@ public abstract class ContentResolver { try { return getContentService().getCurrentSyncs(); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2756,7 +2759,7 @@ public abstract class ContentResolver { try { return getContentService().getCurrentSyncsAsUser(userId); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2771,7 +2774,7 @@ public abstract class ContentResolver { try { return getContentService().getSyncStatus(account, authority, null); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2784,7 +2787,7 @@ public abstract class ContentResolver { try { return getContentService().getSyncStatusAsUser(account, authority, null, userId); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2809,7 +2812,7 @@ public abstract class ContentResolver { try { return getContentService().isSyncPendingAsUser(account, authority, null, userId); } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2841,7 +2844,7 @@ public abstract class ContentResolver { getContentService().addStatusChangeListener(mask, observer); return observer; } catch (RemoteException e) { - throw new RuntimeException("the ContentService should always be reachable", e); + throw e.rethrowFromSystemServer(); } } @@ -2856,8 +2859,7 @@ public abstract class ContentResolver { try { getContentService().removeStatusChangeListener((ISyncStatusObserver.Stub) handle); } catch (RemoteException e) { - // exception ignored; if this is thrown then it means the runtime is in the midst of - // being restarted + throw e.rethrowFromSystemServer(); } } @@ -3027,9 +3029,7 @@ public abstract class ContentResolver { return sContentService; } IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME); - if (false) Log.v("ContentService", "default service binder = " + b); sContentService = IContentService.Stub.asInterface(b); - if (false) Log.v("ContentService", "default service = " + sContentService); return sContentService; } @@ -3038,7 +3038,7 @@ public abstract class ContentResolver { return mPackageName; } - private static IContentService sContentService; + private static volatile IContentService sContentService; private final Context mContext; final String mPackageName; diff --git a/android/content/Context.java b/android/content/Context.java index 920056a8..ede7ee4b 100644 --- a/android/content/Context.java +++ b/android/content/Context.java @@ -3780,7 +3780,7 @@ public abstract class Context { public static final String DROPBOX_SERVICE = "dropbox"; /** - * System service name for the DeviceIdleController. There is no Java API for this. + * System service name for the DeviceIdleManager. * @see #getSystemService(String) * @hide */ diff --git a/android/content/Intent.java b/android/content/Intent.java index 000912cd..f608fcb1 100644 --- a/android/content/Intent.java +++ b/android/content/Intent.java @@ -40,6 +40,7 @@ import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; +import android.os.PersistableBundle; import android.os.Process; import android.os.ResultReceiver; import android.os.ShellCommand; @@ -1814,8 +1815,12 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME"; /** - * Intent extra: A {@link Bundle} of extras for a package being suspended. Will be sent with - * {@link #ACTION_MY_PACKAGE_SUSPENDED}. + * Intent extra: A {@link Bundle} of extras for a package being suspended. Will be sent as an + * extra with {@link #ACTION_MY_PACKAGE_SUSPENDED}. + * + * <p>The contents of this {@link Bundle} are a contract between the suspended app and the + * suspending app, i.e. any app with the permission {@code android.permission.SUSPEND_APPS}. + * This is meant to enable the suspended app to better handle the state of being suspended. * * @see #ACTION_MY_PACKAGE_SUSPENDED * @see #ACTION_MY_PACKAGE_UNSUSPENDED @@ -2282,6 +2287,34 @@ public class Intent implements Parcelable, Cloneable { public static final String ACTION_MY_PACKAGE_SUSPENDED = "android.intent.action.MY_PACKAGE_SUSPENDED"; /** + * Activity Action: Started to show more details about why an application was suspended. + * + * <p>Whenever the system detects an activity launch for a suspended app, it shows a dialog to + * the user to inform them of the state and present them an affordance to start this activity + * action to show more details about the reason for suspension. + * + * <p>Apps holding {@link android.Manifest.permission#SUSPEND_APPS} must declare an activity + * handling this intent and protect it with + * {@link android.Manifest.permission#SEND_SHOW_SUSPENDED_APP_DETAILS}. + * + * <p>Includes an extra {@link #EXTRA_PACKAGE_NAME} which is the name of the suspended package. + * + * <p class="note">This is a protected intent that can only be sent + * by the system. + * + * @see PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle, + * PersistableBundle, String) + * @see PackageManager#isPackageSuspended() + * @see #ACTION_PACKAGES_SUSPENDED + * + * @hide + */ + @SystemApi + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_SHOW_SUSPENDED_APP_DETAILS = + "android.intent.action.SHOW_SUSPENDED_APP_DETAILS"; + + /** * Broadcast Action: Sent to a package that has been unsuspended. * * <p class="note">This is a protected intent that can only be sent @@ -6788,6 +6821,9 @@ public class Intent implements Parcelable, Cloneable { case "--activity-task-on-home": intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME); break; + case "--activity-match-external": + intent.addFlags(Intent.FLAG_ACTIVITY_MATCH_EXTERNAL); + break; case "--receiver-registered-only": intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); break; @@ -6924,7 +6960,7 @@ public class Intent implements Parcelable, Cloneable { " [--activity-no-user-action] [--activity-previous-is-top]", " [--activity-reorder-to-front] [--activity-reset-task-if-needed]", " [--activity-single-top] [--activity-clear-task]", - " [--activity-task-on-home]", + " [--activity-task-on-home] [--activity-match-external]", " [--receiver-registered-only] [--receiver-replace-pending]", " [--receiver-foreground] [--receiver-no-abort]", " [--receiver-include-background]", diff --git a/android/content/QuickViewConstants.java b/android/content/QuickViewConstants.java index a25513de..132d43f2 100644 --- a/android/content/QuickViewConstants.java +++ b/android/content/QuickViewConstants.java @@ -45,8 +45,8 @@ public class QuickViewConstants { * Feature to delete an individual document. Quick viewer implementations must use * Storage Access Framework to both verify delete permission and to delete content. * - * @see DocumentsContract#Document#FLAG_SUPPORTS_DELETE - * @see DocumentsContract#deleteDocument(ContentResolver resolver, Uri documentUri) + * @see DocumentsContract.Document#FLAG_SUPPORTS_DELETE + * @see DocumentsContract#deleteDocument(ContentResolver, Uri) */ public static final String FEATURE_DELETE = "android:delete"; diff --git a/android/content/pm/ApplicationInfo.java b/android/content/pm/ApplicationInfo.java index e85058df..d65e051b 100644 --- a/android/content/pm/ApplicationInfo.java +++ b/android/content/pm/ApplicationInfo.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.Environment; import android.os.Parcel; import android.os.Parcelable; @@ -590,26 +591,33 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int PRIVATE_FLAG_VIRTUAL_PRELOAD = 1 << 16; /** - * Value for {@linl #privateFlags}: whether this app is pre-installed on the + * Value for {@link #privateFlags}: whether this app is pre-installed on the * OEM partition of the system image. * @hide */ public static final int PRIVATE_FLAG_OEM = 1 << 17; /** - * Value for {@linl #privateFlags}: whether this app is pre-installed on the + * Value for {@link #privateFlags}: whether this app is pre-installed on the * vendor partition of the system image. * @hide */ public static final int PRIVATE_FLAG_VENDOR = 1 << 18; /** - * Value for {@linl #privateFlags}: whether this app is pre-installed on the + * Value for {@link #privateFlags}: whether this app is pre-installed on the * product partition of the system image. * @hide */ public static final int PRIVATE_FLAG_PRODUCT = 1 << 19; + /** + * Value for {@link #privateFlags}: whether this app is signed with the + * platform key. + * @hide + */ + public static final int PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY = 1 << 20; + /** @hide */ @IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = { PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE, @@ -629,6 +637,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { PRIVATE_FLAG_PRIVILEGED, PRIVATE_FLAG_PRODUCT, PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, + PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY, PRIVATE_FLAG_STATIC_SHARED_LIBRARY, PRIVATE_FLAG_VENDOR, PRIVATE_FLAG_VIRTUAL_PRELOAD, @@ -904,7 +913,17 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * The app's declared version code. * @hide */ - public long versionCode; + public long longVersionCode; + + /** + * An integer representation of the app's declared version code. This is being left in place as + * some apps were using reflection to access it before the move to long in + * {@link android.os.Build.VERSION_CODES#P} + * @deprecated Use {@link #longVersionCode} instead. + * @hide + */ + @Deprecated + public int versionCode; /** * The user-visible SDK version (ex. 26) of the framework against which the application claims @@ -1114,11 +1133,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public static final int HIDDEN_API_ENFORCEMENT_NONE = 0; /** - * Light grey list enforcement, the strictest option. Enforces the light grey, dark grey and - * black lists. + * No API enforcement, but enable the detection logic and warnings. Observed behaviour is the + * same as {@link #HIDDEN_API_ENFORCEMENT_NONE} but you may see warnings in the log when APIs + * are accessed. * @hide * */ - public static final int HIDDEN_API_ENFORCEMENT_ALL_LISTS = 1; + public static final int HIDDEN_API_ENFORCEMENT_JUST_WARN = 1; /** * Dark grey list enforcement. Enforces the dark grey and black lists * @hide @@ -1140,14 +1160,15 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { @IntDef(prefix = { "HIDDEN_API_ENFORCEMENT_" }, value = { HIDDEN_API_ENFORCEMENT_DEFAULT, HIDDEN_API_ENFORCEMENT_NONE, - HIDDEN_API_ENFORCEMENT_ALL_LISTS, + HIDDEN_API_ENFORCEMENT_JUST_WARN, HIDDEN_API_ENFORCEMENT_DARK_GREY_AND_BLACK, HIDDEN_API_ENFORCEMENT_BLACK, }) @Retention(RetentionPolicy.SOURCE) public @interface HiddenApiEnforcementPolicy {} - private boolean isValidHiddenApiEnforcementPolicy(int policy) { + /** @hide */ + public static boolean isValidHiddenApiEnforcementPolicy(int policy) { return policy >= HIDDEN_API_ENFORCEMENT_DEFAULT && policy <= HIDDEN_API_ENFORCEMENT_MAX; } @@ -1214,7 +1235,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { pw.println(prefix + "enabled=" + enabled + " minSdkVersion=" + minSdkVersion + " targetSdkVersion=" + targetSdkVersion - + " versionCode=" + versionCode + + " versionCode=" + longVersionCode + " targetSandboxVersion=" + targetSandboxVersion); if ((dumpFlags & DUMP_FLAG_DETAILS) != 0) { if (manageSpaceActivityName != null) { @@ -1287,7 +1308,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { proto.write(ApplicationInfoProto.Version.ENABLED, enabled); proto.write(ApplicationInfoProto.Version.MIN_SDK_VERSION, minSdkVersion); proto.write(ApplicationInfoProto.Version.TARGET_SDK_VERSION, targetSdkVersion); - proto.write(ApplicationInfoProto.Version.VERSION_CODE, versionCode); + proto.write(ApplicationInfoProto.Version.VERSION_CODE, longVersionCode); proto.write(ApplicationInfoProto.Version.TARGET_SANDBOX_VERSION, targetSandboxVersion); proto.end(versionToken); @@ -1421,7 +1442,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { uid = orig.uid; minSdkVersion = orig.minSdkVersion; targetSdkVersion = orig.targetSdkVersion; - versionCode = orig.versionCode; + setVersionCode(orig.longVersionCode); enabled = orig.enabled; enabledSetting = orig.enabledSetting; installLocation = orig.installLocation; @@ -1495,7 +1516,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeInt(uid); dest.writeInt(minSdkVersion); dest.writeInt(targetSdkVersion); - dest.writeLong(versionCode); + dest.writeLong(longVersionCode); dest.writeInt(enabled ? 1 : 0); dest.writeInt(enabledSetting); dest.writeInt(installLocation); @@ -1566,7 +1587,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { uid = source.readInt(); minSdkVersion = source.readInt(); targetSdkVersion = source.readInt(); - versionCode = source.readLong(); + setVersionCode(source.readLong()); enabled = source.readInt() != 0; enabledSetting = source.readInt(); installLocation = source.readInt(); @@ -1658,17 +1679,26 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { return SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName); } + private boolean isAllowedToUseHiddenApis() { + return isSignedWithPlatformKey() + || (isPackageWhitelistedForHiddenApis() && (isSystemApp() || isUpdatedSystemApp())); + } + /** * @hide */ public @HiddenApiEnforcementPolicy int getHiddenApiEnforcementPolicy() { + if (isAllowedToUseHiddenApis()) { + return HIDDEN_API_ENFORCEMENT_NONE; + } if (mHiddenApiPolicy != HIDDEN_API_ENFORCEMENT_DEFAULT) { return mHiddenApiPolicy; } - if (isPackageWhitelistedForHiddenApis() && (isSystemApp() || isUpdatedSystemApp())) { - return HIDDEN_API_ENFORCEMENT_NONE; + if (targetSdkVersion < Build.VERSION_CODES.P) { + return HIDDEN_API_ENFORCEMENT_BLACK; + } else { + return HIDDEN_API_ENFORCEMENT_DARK_GREY_AND_BLACK; } - return HIDDEN_API_ENFORCEMENT_BLACK; } /** @@ -1682,6 +1712,39 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { } /** + * Updates the hidden API enforcement policy for this app from the given values, if appropriate. + * + * This will have no effect if this app is not subject to hidden API enforcement, i.e. if it + * is on the package whitelist. + * + * @param policyPreP configured policy for pre-P apps, or {@link + * #HIDDEN_API_ENFORCEMENT_DEFAULT} if nothing configured. + * @param policyP configured policy for apps targeting P or later, or {@link + * #HIDDEN_API_ENFORCEMENT_DEFAULT} if nothing configured. + * @hide + */ + public void maybeUpdateHiddenApiEnforcementPolicy( + @HiddenApiEnforcementPolicy int policyPreP, @HiddenApiEnforcementPolicy int policyP) { + if (isPackageWhitelistedForHiddenApis()) { + return; + } + if (targetSdkVersion < Build.VERSION_CODES.P) { + setHiddenApiEnforcementPolicy(policyPreP); + } else if (targetSdkVersion >= Build.VERSION_CODES.P) { + setHiddenApiEnforcementPolicy(policyP); + } + + } + + /** + * @hide + */ + public void setVersionCode(long newVersionCode) { + longVersionCode = newVersionCode; + versionCode = (int) newVersionCode; + } + + /** * @hide */ @Override @@ -1758,6 +1821,11 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { } /** @hide */ + public boolean isSignedWithPlatformKey() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY) != 0; + } + + /** @hide */ @TestApi public boolean isPrivilegedApp() { return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; diff --git a/android/content/pm/LauncherApps.java b/android/content/pm/LauncherApps.java index 9aace2e7..8223363a 100644 --- a/android/content/pm/LauncherApps.java +++ b/android/content/pm/LauncherApps.java @@ -212,7 +212,7 @@ public class LauncherApps { * an applicaton. * * <p>Note: On devices running {@link android.os.Build.VERSION_CODES#P Android P} or higher, - * any apps that override {@link #onPackagesSuspended(String[], Bundle, UserHandle)} will + * any apps that override {@link #onPackagesSuspended(String[], UserHandle, Bundle)} will * not receive this callback. * * @param packageNames The names of the packages that have just been @@ -226,15 +226,20 @@ public class LauncherApps { * Indicates that one or more packages have been suspended. A device administrator or an app * with {@code android.permission.SUSPEND_APPS} can do this. * + * <p>A suspending app with the permission {@code android.permission.SUSPEND_APPS} can + * optionally provide a {@link Bundle} of extra information that it deems helpful for the + * launcher to handle the suspended state of these packages. The contents of this + * {@link Bundle} supposed to be a contract between the suspending app and the launcher. + * * @param packageNames The names of the packages that have just been suspended. - * @param launcherExtras A {@link Bundle} of extras for the launcher. * @param user the user for which the given packages were suspended. - * + * @param launcherExtras A {@link Bundle} of extras for the launcher, if provided to the + * system, {@code null} otherwise. * @see PackageManager#isPackageSuspended() * @see #getSuspendedPackageLauncherExtras(String, UserHandle) */ - public void onPackagesSuspended(String[] packageNames, @Nullable Bundle launcherExtras, - UserHandle user) { + public void onPackagesSuspended(String[] packageNames, UserHandle user, + @Nullable Bundle launcherExtras) { onPackagesSuspended(packageNames, user); } @@ -662,6 +667,9 @@ public class LauncherApps { * {@code PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle, * PersistableBundle, String)}. * + * <p>The contents of this {@link Bundle} are supposed to be a contract between the suspending + * app and the launcher. + * * <p>Note: This just returns whatever extras were provided to the system, <em>which might * even be {@code null}.</em> * @@ -670,7 +678,7 @@ public class LauncherApps { * @return A {@link Bundle} of launcher extras. Or {@code null} if the package is not currently * suspended. * - * @see Callback#onPackagesSuspended(String[], Bundle, UserHandle) + * @see Callback#onPackagesSuspended(String[], UserHandle, Bundle) * @see PackageManager#isPackageSuspended() */ public @Nullable Bundle getSuspendedPackageLauncherExtras(String packageName, UserHandle user) { @@ -1298,8 +1306,8 @@ public class LauncherApps { mCallback.onPackagesUnavailable(info.packageNames, info.user, info.replacing); break; case MSG_SUSPENDED: - mCallback.onPackagesSuspended(info.packageNames, info.launcherExtras, - info.user); + mCallback.onPackagesSuspended(info.packageNames, info.user, info.launcherExtras + ); break; case MSG_UNSUSPENDED: mCallback.onPackagesUnsuspended(info.packageNames, info.user); diff --git a/android/content/pm/PackageInfo.java b/android/content/pm/PackageInfo.java index 627ceb78..5f9f8f1f 100644 --- a/android/content/pm/PackageInfo.java +++ b/android/content/pm/PackageInfo.java @@ -244,7 +244,7 @@ public class PackageInfo implements Parcelable { * the first position to be the same across updates. * * <strong>Deprecated</strong> This has been replaced by the - * {@link PackageInfo#signingCertificateHistory} field, which takes into + * {@link PackageInfo#signingInfo} field, which takes into * account signing certificate rotation. For backwards compatibility in * the event of signing certificate rotation, this will return the oldest * reported signing certificate, so that an application will appear to @@ -256,29 +256,15 @@ public class PackageInfo implements Parcelable { public Signature[] signatures; /** - * Array of all signatures arrays read from the package file, potentially + * Signing information read from the package file, potentially * including past signing certificates no longer used after signing - * certificate rotation. Though signing certificate rotation is only - * available for apps with a single signing certificate, this provides an - * array of arrays so that packages signed with multiple signing - * certificates can still return all signers. This is only filled in if + * certificate rotation. This is only filled in if * the flag {@link PackageManager#GET_SIGNING_CERTIFICATES} was set. * - * A package must be singed with at least one certificate, which is at - * position zero in the array. An application may be signed by multiple - * certificates, which would be in the array at position zero in an - * indeterminate order. A package may also have a history of certificates - * due to signing certificate rotation. In this case, the array will be - * populated by a series of single-entry arrays corresponding to a signing - * certificate of the package. - * - * <strong>Note:</strong> Signature ordering is not guaranteed to be - * stable which means that a package signed with certificates A and B is - * equivalent to being signed with certificates B and A. This means that - * in case multiple signatures are reported you cannot assume the one at - * the first position will be the same across updates. + * Use this field instead of the deprecated {@code signatures} field. + * See {@link SigningInfo} for more information on its contents. */ - public Signature[][] signingCertificateHistory; + public SigningInfo signingInfo; /** * Application specified preferred configuration @@ -476,17 +462,11 @@ public class PackageInfo implements Parcelable { dest.writeBoolean(mOverlayIsStatic); dest.writeInt(compileSdkVersion); dest.writeString(compileSdkVersionCodename); - writeSigningCertificateHistoryToParcel(dest, parcelableFlags); - } - - private void writeSigningCertificateHistoryToParcel(Parcel dest, int parcelableFlags) { - if (signingCertificateHistory != null) { - dest.writeInt(signingCertificateHistory.length); - for (int i = 0; i < signingCertificateHistory.length; i++) { - dest.writeTypedArray(signingCertificateHistory[i], parcelableFlags); - } + if (signingInfo != null) { + dest.writeInt(1); + signingInfo.writeToParcel(dest, parcelableFlags); } else { - dest.writeInt(-1); + dest.writeInt(0); } } @@ -544,7 +524,10 @@ public class PackageInfo implements Parcelable { mOverlayIsStatic = source.readBoolean(); compileSdkVersion = source.readInt(); compileSdkVersionCodename = source.readString(); - readSigningCertificateHistoryFromParcel(source); + int hasSigningInfo = source.readInt(); + if (hasSigningInfo != 0) { + signingInfo = SigningInfo.CREATOR.createFromParcel(source); + } // The component lists were flattened with the redundant ApplicationInfo // instances omitted. Distribute the canonical one here as appropriate. @@ -556,16 +539,6 @@ public class PackageInfo implements Parcelable { } } - private void readSigningCertificateHistoryFromParcel(Parcel source) { - int len = source.readInt(); - if (len != -1) { - signingCertificateHistory = new Signature[len][]; - for (int i = 0; i < len; i++) { - signingCertificateHistory[i] = source.createTypedArray(Signature.CREATOR); - } - } - } - private void propagateApplicationInfo(ApplicationInfo appInfo, ComponentInfo[] components) { if (components != null) { for (ComponentInfo ci : components) { diff --git a/android/content/pm/PackageManager.java b/android/content/pm/PackageManager.java index 491f0af2..9d3b53f2 100644 --- a/android/content/pm/PackageManager.java +++ b/android/content/pm/PackageManager.java @@ -2629,6 +2629,17 @@ public abstract class PackageManager { "android.hardware.strongbox_keystore"; /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: + * The device has a Keymaster implementation that supports Device ID attestation. + * + * @see DevicePolicyManager#isDeviceIdAttestationSupported + * @hide + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_DEVICE_ID_ATTESTATION = + "android.software.device_id_attestation"; + + /** * Action to external storage service to clean out removed apps. * @hide */ @@ -3941,6 +3952,7 @@ public abstract class PackageManager { * * @hide */ + @TestApi public abstract @NonNull String getServicesSystemSharedLibraryPackageName(); /** @@ -3950,6 +3962,7 @@ public abstract class PackageManager { * * @hide */ + @TestApi public abstract @NonNull String getSharedSystemSharedLibraryPackageName(); /** @@ -5558,7 +5571,8 @@ public abstract class PackageManager { * @param packageName The name of the package to get the suspended status of. * @param userId The user id. * @return {@code true} if the package is suspended or {@code false} if the package is not - * suspended or could not be found. + * suspended. + * @throws IllegalArgumentException if the package was not found. * @hide */ public abstract boolean isPackageSuspendedForUser(String packageName, int userId); @@ -5567,12 +5581,13 @@ public abstract class PackageManager { * Query if an app is currently suspended. * * @return {@code true} if the given package is suspended, {@code false} otherwise + * @throws NameNotFoundException if the package could not be found. * * @see #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle, String) * @hide */ @SystemApi - public boolean isPackageSuspended(String packageName) { + public boolean isPackageSuspended(String packageName) throws NameNotFoundException { throw new UnsupportedOperationException("isPackageSuspended not implemented"); } @@ -5603,51 +5618,16 @@ public abstract class PackageManager { } /** - * Retrieve the {@link PersistableBundle} that was passed as {@code appExtras} when the given - * package was suspended. - * - * <p> The caller must hold permission {@link Manifest.permission#SUSPEND_APPS} to use this - * api.</p> - * - * @param packageName The package to retrieve extras for. - * @return The {@code appExtras} for the suspended package. - * - * @see #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle, String) - * @hide - */ - @SystemApi - @RequiresPermission(Manifest.permission.SUSPEND_APPS) - public @Nullable PersistableBundle getSuspendedPackageAppExtras(String packageName) { - throw new UnsupportedOperationException("getSuspendedPackageAppExtras not implemented"); - } - - /** - * Set the app extras for a suspended package. This method can be used to update the appExtras - * for a package that was earlier suspended using - * {@link #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle, - * String)} - * Does nothing if the given package is not already in a suspended state. + * Returns a {@link Bundle} of extras that was meant to be sent to the calling app when it was + * suspended. An app with the permission {@code android.permission.SUSPEND_APPS} can supply this + * to the system at the time of suspending an app. * - * @param packageName The package for which the appExtras need to be updated - * @param appExtras The new appExtras for the given package + * <p>This is the same {@link Bundle} that is sent along with the broadcast + * {@link Intent#ACTION_MY_PACKAGE_SUSPENDED}, whenever the app is suspended. The contents of + * this {@link Bundle} are a contract between the suspended app and the suspending app. * - * @see #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle, String) - * - * @hide - */ - @SystemApi - @RequiresPermission(Manifest.permission.SUSPEND_APPS) - public void setSuspendedPackageAppExtras(String packageName, - @Nullable PersistableBundle appExtras) { - throw new UnsupportedOperationException("setSuspendedPackageAppExtras not implemented"); - } - - /** - * Returns any extra information supplied as {@code appExtras} to the system when the calling - * app was suspended. - * - * <p>Note: If no extras were supplied to the system, this method will return {@code null}, even - * when the calling app has been suspended.</p> + * <p>Note: These extras are optional, so if no extras were supplied to the system, this method + * will return {@code null}, even when the calling app has been suspended. * * @return A {@link Bundle} containing the extras for the app, or {@code null} if the * package is not currently suspended. @@ -5655,6 +5635,7 @@ public abstract class PackageManager { * @see #isPackageSuspended() * @see Intent#ACTION_MY_PACKAGE_UNSUSPENDED * @see Intent#ACTION_MY_PACKAGE_SUSPENDED + * @see Intent#EXTRA_SUSPENDED_PACKAGE_EXTRAS */ public @Nullable Bundle getSuspendedPackageAppExtras() { throw new UnsupportedOperationException("getSuspendedPackageAppExtras not implemented"); @@ -6118,7 +6099,9 @@ public abstract class PackageManager { * signed. This should be used instead of {@code getPackageInfo} with {@code GET_SIGNATURES} * since it takes into account the possibility of signing certificate rotation, except in the * case of packages that are signed by multiple certificates, for which signing certificate - * rotation is not supported. + * rotation is not supported. This method is analogous to using {@code getPackageInfo} with + * {@code GET_SIGNING_CERTIFICATES} and then searching through the resulting {@code + * signingCertificateHistory} field to see if the desired certificate is present. * * @param packageName package whose signing certificates to check * @param certificate signing certificate for which to search @@ -6132,13 +6115,19 @@ public abstract class PackageManager { } /** - * Searches the set of signing certificates by which the given uid has proven to have been - * signed. This should be used instead of {@code getPackageInfo} with {@code GET_SIGNATURES} + * Searches the set of signing certificates by which the package(s) for the given uid has proven + * to have been signed. For multiple packages sharing the same uid, this will return the + * signing certificates found in the signing history of the "newest" package, where "newest" + * indicates the package with the newest signing certificate in the shared uid group. This + * method should be used instead of {@code getPackageInfo} with {@code GET_SIGNATURES} * since it takes into account the possibility of signing certificate rotation, except in the * case of packages that are signed by multiple certificates, for which signing certificate - * rotation is not supported. + * rotation is not supported. This method is analogous to using {@code getPackagesForUid} + * followed by {@code getPackageInfo} with {@code GET_SIGNING_CERTIFICATES}, selecting the + * {@code PackageInfo} of the newest-signed bpackage , and finally searching through the + * resulting {@code signingCertificateHistory} field to see if the desired certificate is there. * - * @param uid package whose signing certificates to check + * @param uid uid whose signing certificates to check * @param certificate signing certificate for which to search * @param type representation of the {@code certificate} * @return true if this package was or is signed by exactly the certificate {@code certificate} diff --git a/android/content/pm/PackageManagerInternal.java b/android/content/pm/PackageManagerInternal.java index c9b78c08..a9d09110 100644 --- a/android/content/pm/PackageManagerInternal.java +++ b/android/content/pm/PackageManagerInternal.java @@ -191,10 +191,10 @@ public abstract class PackageManagerInternal { /** * Retrieve launcher extras for a suspended package provided to the system in * {@link PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle, - * PersistableBundle, String)} + * PersistableBundle, String)}. * * @param packageName The package for which to return launcher extras. - * @param userId The user for which to check, + * @param userId The user for which to check. * @return The launcher extras. * * @see PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle, @@ -205,6 +205,38 @@ public abstract class PackageManagerInternal { int userId); /** + * Internal api to query the suspended state of a package. + * @param packageName The package to check. + * @param userId The user id to check for. + * @return {@code true} if the package is suspended, {@code false} otherwise. + * @see PackageManager#isPackageSuspended(String) + */ + public abstract boolean isPackageSuspended(String packageName, int userId); + + /** + * Get the name of the package that suspended the given package. Packages can be suspended by + * device administrators or apps holding {@link android.Manifest.permission#MANAGE_USERS} or + * {@link android.Manifest.permission#SUSPEND_APPS}. + * + * @param suspendedPackage The package that has been suspended. + * @param userId The user for which to check. + * @return Name of the package that suspended the given package. Returns {@code null} if the + * given package is not currently suspended and the platform package name - i.e. + * {@code "android"} - if the package was suspended by a device admin. + */ + public abstract String getSuspendingPackage(String suspendedPackage, int userId); + + /** + * Get the dialog message to be shown to the user when they try to launch a suspended + * application. + * + * @param suspendedPackage The package that has been suspended. + * @param userId The user for which to check. + * @return The dialog message to be shown to the user. + */ + public abstract String getSuspendedDialogMessage(String suspendedPackage, int userId); + + /** * Do a straight uid lookup for the given package/application in the given user. * @see PackageManager#getPackageUidAsUser(String, int, int) * @return The app's uid, or < 0 if the package was not found in that user @@ -429,7 +461,7 @@ public abstract class PackageManagerInternal { * Resolves an activity intent, allowing instant apps to be resolved. */ public abstract ResolveInfo resolveIntent(Intent intent, String resolvedType, - int flags, int userId, boolean resolveForStart); + int flags, int userId, boolean resolveForStart, int filterCallingUid); /** * Resolves a service intent, allowing instant apps to be resolved. diff --git a/android/content/pm/PackageParser.java b/android/content/pm/PackageParser.java index 2f0faf25..453a74aa 100644 --- a/android/content/pm/PackageParser.java +++ b/android/content/pm/PackageParser.java @@ -810,21 +810,11 @@ public class PackageParser { // replacement for GET_SIGNATURES if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) { - if (p.mSigningDetails.hasPastSigningCertificates()) { - // Package has included signing certificate rotation information. Convert each - // entry to an array - int numberOfSigs = p.mSigningDetails.pastSigningCertificates.length; - pi.signingCertificateHistory = new Signature[numberOfSigs][]; - for (int i = 0; i < numberOfSigs; i++) { - pi.signingCertificateHistory[i] = - new Signature[] { p.mSigningDetails.pastSigningCertificates[i] }; - } - } else if (p.mSigningDetails.hasSignatures()) { - // otherwise keep old behavior - int numberOfSigs = p.mSigningDetails.signatures.length; - pi.signingCertificateHistory = new Signature[1][numberOfSigs]; - System.arraycopy(p.mSigningDetails.signatures, 0, - pi.signingCertificateHistory[0], 0, numberOfSigs); + if (p.mSigningDetails != SigningDetails.UNKNOWN) { + // only return a valid SigningInfo if there is signing information to report + pi.signingInfo = new SigningInfo(p.mSigningDetails); + } else { + pi.signingInfo = null; } } return pi; @@ -1918,7 +1908,7 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifest_versionCode, 0); pkg.mVersionCodeMajor = sa.getInteger( com.android.internal.R.styleable.AndroidManifest_versionCodeMajor, 0); - pkg.applicationInfo.versionCode = pkg.getLongVersionCode(); + pkg.applicationInfo.setVersionCode(pkg.getLongVersionCode()); pkg.baseRevisionCode = sa.getInteger( com.android.internal.R.styleable.AndroidManifest_revisionCode, 0); pkg.mVersionName = sa.getNonConfigurationString( @@ -2726,7 +2716,7 @@ public class PackageParser { // Fot apps targeting O-MR1 we require explicit enumeration of all certs. String[] additionalCertSha256Digests = EmptyArray.STRING; - if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.O) { + if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O_MR1) { additionalCertSha256Digests = parseAdditionalCertificates(res, parser, outError); if (additionalCertSha256Digests == null) { return false; diff --git a/android/content/pm/PackageSharedLibraryUpdater.java b/android/content/pm/PackageSharedLibraryUpdater.java index fa894320..b14b321a 100644 --- a/android/content/pm/PackageSharedLibraryUpdater.java +++ b/android/content/pm/PackageSharedLibraryUpdater.java @@ -62,7 +62,7 @@ public abstract class PackageSharedLibraryUpdater { static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(PackageParser.Package pkg) { int targetSdkVersion = pkg.applicationInfo.targetSdkVersion; - return targetSdkVersion <= Build.VERSION_CODES.O_MR1; + return targetSdkVersion < Build.VERSION_CODES.P; } /** diff --git a/android/content/pm/PackageUserState.java b/android/content/pm/PackageUserState.java index f7b6e091..f471a1d9 100644 --- a/android/content/pm/PackageUserState.java +++ b/android/content/pm/PackageUserState.java @@ -34,6 +34,7 @@ import android.util.ArraySet; import com.android.internal.util.ArrayUtils; import java.util.Arrays; +import java.util.Objects; /** * Per-user state information about a package. @@ -47,6 +48,7 @@ public class PackageUserState { public boolean hidden; // Is the app restricted by owner / admin public boolean suspended; public String suspendingPackage; + public String dialogMessage; // Message to show when a suspended package launch attempt is made public PersistableBundle suspendedAppExtras; public PersistableBundle suspendedLauncherExtras; public boolean instantApp; @@ -82,6 +84,7 @@ public class PackageUserState { hidden = o.hidden; suspended = o.suspended; suspendingPackage = o.suspendingPackage; + dialogMessage = o.dialogMessage; suspendedAppExtras = o.suspendedAppExtras; suspendedLauncherExtras = o.suspendedLauncherExtras; instantApp = o.instantApp; @@ -208,6 +211,9 @@ public class PackageUserState { || !suspendingPackage.equals(oldState.suspendingPackage)) { return false; } + if (!Objects.equals(dialogMessage, oldState.dialogMessage)) { + return false; + } if (!BaseBundle.kindofEquals(suspendedAppExtras, oldState.suspendedAppExtras)) { return false; diff --git a/android/content/pm/SigningInfo.java b/android/content/pm/SigningInfo.java new file mode 100644 index 00000000..ef874035 --- /dev/null +++ b/android/content/pm/SigningInfo.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2018 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.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Information pertaining to the signing certificates used to sign a package. + */ +public final class SigningInfo implements Parcelable { + + @NonNull + private final PackageParser.SigningDetails mSigningDetails; + + public SigningInfo() { + mSigningDetails = PackageParser.SigningDetails.UNKNOWN; + } + + /** + * @hide only packagemanager should be populating this + */ + public SigningInfo(PackageParser.SigningDetails signingDetails) { + mSigningDetails = new PackageParser.SigningDetails(signingDetails); + } + + public SigningInfo(SigningInfo orig) { + mSigningDetails = new PackageParser.SigningDetails(orig.mSigningDetails); + } + + private SigningInfo(Parcel source) { + mSigningDetails = PackageParser.SigningDetails.CREATOR.createFromParcel(source); + } + + /** + * Although relatively uncommon, packages may be signed by more than one signer, in which case + * their identity is viewed as being the set of all signers, not just any one. + */ + public boolean hasMultipleSigners() { + return mSigningDetails.signatures != null && mSigningDetails.signatures.length > 1; + } + + /** + * APK Signature Scheme v3 enables packages to provide a proof-of-rotation record that the + * platform verifies, and uses, to allow the use of new signing certificates. This is only + * available to packages that are not signed by multiple signers. In the event of a change to a + * new signing certificate, the package's past signing certificates are presented as well. Any + * check of a package's signing certificate should also include a search through its entire + * signing history, since it could change to a new signing certificate at any time. + */ + public boolean hasPastSigningCertificates() { + return mSigningDetails.signatures != null + && mSigningDetails.pastSigningCertificates != null; + } + + /** + * Returns the signing certificates this package has proven it is authorized to use. This + * includes both the signing certificate associated with the signer of the package and the past + * signing certificates it included as its proof of signing certificate rotation. This method + * is the preferred replacement for the {@code GET_SIGNATURES} flag used with {@link + * PackageManager#getPackageInfo(String, int)}. When determining if a package is signed by a + * desired certificate, the returned array should be checked to determine if it is one of the + * entries. + * + * <note> + * This method returns null if the package is signed by multiple signing certificates, as + * opposed to being signed by one current signer and also providing the history of past + * signing certificates. {@link #hasMultipleSigners()} may be used to determine if this + * package is signed by multiple signers. Packages which are signed by multiple signers + * cannot change their signing certificates and their {@code Signature} array should be + * checked to make sure that every entry matches the looked-for signing certificates. + * </note> + */ + public Signature[] getSigningCertificateHistory() { + if (hasMultipleSigners()) { + return null; + } else if (!hasPastSigningCertificates()) { + + // this package is only signed by one signer with no history, return it + return mSigningDetails.signatures; + } else { + + // this package has provided proof of past signing certificates, include them + return mSigningDetails.pastSigningCertificates; + } + } + + /** + * Returns the signing certificates used to sign the APK contents of this application. Not + * including any past signing certificates the package proved it is authorized to use. + * <note> + * This method should not be used unless {@link #hasMultipleSigners()} returns true, + * indicating that {@link #getSigningCertificateHistory()} cannot be used, otherwise {@link + * #getSigningCertificateHistory()} should be preferred. + * </note> + */ + public Signature[] getApkContentsSigners() { + return mSigningDetails.signatures; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int parcelableFlags) { + mSigningDetails.writeToParcel(dest, parcelableFlags); + } + + public static final Parcelable.Creator<SigningInfo> CREATOR = + new Parcelable.Creator<SigningInfo>() { + @Override + public SigningInfo createFromParcel(Parcel source) { + return new SigningInfo(source); + } + + @Override + public SigningInfo[] newArray(int size) { + return new SigningInfo[size]; + } + }; +} |