From 16073b8a7c6de7f7e982d3b603bb22efaff4437e Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Fri, 23 Mar 2018 10:05:01 +0000 Subject: [PATCH] More flexible API enforcement policy. This CL adds the basics to set black, dark gray or light gray list enforcement, rather than just black as before. It's not possible to actually set the policy per-package yet. PackageDexOptimizer still uses a single bit, for API checks on/off, rather than the new enum. It assumes blacklist enforcement internally. This can be improved in a follow up CL. (cherry-picked from commit e52130ae4cf3b046b38a09fc7cc7712f5b7fb83d) Test: m Test: Boot device BUG: 73337509 Change-Id: Ic0d5b8fa631c2bd583b6fc52b2ee3708c8113f59 Merged-In: Idd73c9938592c5c4d67cfb9efefdffed0dd5f262 --- .../android/content/pm/ApplicationInfo.java | 83 +++++++++++++++++-- core/java/com/android/internal/os/Zygote.java | 17 +++- .../server/am/ActivityManagerService.java | 15 ++-- .../server/pm/PackageDexOptimizer.java | 7 +- 4 files changed, 107 insertions(+), 15 deletions(-) diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 8ea81a4aa99b0..ebc88ff7116b5 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -1046,6 +1046,58 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { /** @hide */ public String[] splitClassLoaderNames; + /** + * Represents the default policy. The actual policy used will depend on other properties of + * the application, e.g. the target SDK version. + * @hide + */ + public static final int HIDDEN_API_ENFORCEMENT_DEFAULT = -1; + /** + * No API enforcement; the app can access the entire internal private API. Only for use by + * system apps. + * @hide + */ + 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. + * @hide + * */ + public static final int HIDDEN_API_ENFORCEMENT_ALL_LISTS = 1; + /** + * Dark grey list enforcement. Enforces the dark grey and black lists + * @hide + */ + public static final int HIDDEN_API_ENFORCEMENT_DARK_GREY_AND_BLACK = 2; + /** + * Blacklist enforcement only. + * @hide + */ + public static final int HIDDEN_API_ENFORCEMENT_BLACK = 3; + + private static final int HIDDEN_API_ENFORCEMENT_MAX = HIDDEN_API_ENFORCEMENT_BLACK; + + /** + * Values in this IntDef MUST be kept in sync with enum hiddenapi::EnforcementPolicy in + * art/runtime/hidden_api.h + * @hide + */ + @IntDef(prefix = { "HIDDEN_API_ENFORCEMENT_" }, value = { + HIDDEN_API_ENFORCEMENT_DEFAULT, + HIDDEN_API_ENFORCEMENT_NONE, + HIDDEN_API_ENFORCEMENT_ALL_LISTS, + HIDDEN_API_ENFORCEMENT_DARK_GREY_AND_BLACK, + HIDDEN_API_ENFORCEMENT_BLACK, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface HiddenApiEnforcementPolicy {} + + private boolean isValidHiddenApiEnforcementPolicy(int policy) { + return policy >= HIDDEN_API_ENFORCEMENT_DEFAULT && policy <= HIDDEN_API_ENFORCEMENT_MAX; + } + + private int mHiddenApiPolicy = HIDDEN_API_ENFORCEMENT_DEFAULT; + public void dump(Printer pw, String prefix) { dump(pw, prefix, DUMP_FLAG_ALL); } @@ -1133,6 +1185,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { if (category != CATEGORY_UNDEFINED) { pw.println(prefix + "category=" + category); } + pw.println(prefix + "HiddenApiEnforcementPolicy=" + getHiddenApiEnforcementPolicy()); } super.dumpBack(pw, prefix); } @@ -1228,6 +1281,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { targetSandboxVersion = orig.targetSandboxVersion; classLoaderName = orig.classLoaderName; splitClassLoaderNames = orig.splitClassLoaderNames; + mHiddenApiPolicy = orig.mHiddenApiPolicy; } public String toString() { @@ -1298,6 +1352,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeInt(targetSandboxVersion); dest.writeString(classLoaderName); dest.writeStringArray(splitClassLoaderNames); + dest.writeInt(mHiddenApiPolicy); } public static final Parcelable.Creator CREATOR @@ -1365,6 +1420,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { targetSandboxVersion = source.readInt(); classLoaderName = source.readString(); splitClassLoaderNames = source.readStringArray(); + mHiddenApiPolicy = source.readInt(); } /** @@ -1456,14 +1512,31 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { } } + private boolean isPackageWhitelistedForHiddenApis() { + return SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName); + } + /** * @hide */ - public boolean isAllowedToUseHiddenApi() { - boolean whitelisted = - SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName); - return isSystemApp() || // TODO get rid of this once the whitelist has been populated - (whitelisted && (isSystemApp() || isUpdatedSystemApp())); + public @HiddenApiEnforcementPolicy int getHiddenApiEnforcementPolicy() { + if (mHiddenApiPolicy != HIDDEN_API_ENFORCEMENT_DEFAULT) { + return mHiddenApiPolicy; + } + if (isPackageWhitelistedForHiddenApis() && (isSystemApp() || isUpdatedSystemApp())) { + return HIDDEN_API_ENFORCEMENT_NONE; + } + return HIDDEN_API_ENFORCEMENT_BLACK; + } + + /** + * @hide + */ + public void setHiddenApiEnforcementPolicy(@HiddenApiEnforcementPolicy int policy) { + if (!isValidHiddenApiEnforcementPolicy(policy)) { + throw new IllegalArgumentException("Invalid API enforcement policy: " + policy); + } + mHiddenApiPolicy = policy; } /** diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index e23cbf815b873..0d1088896f407 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -55,10 +55,21 @@ public final class Zygote { public static final int DISABLE_VERIFIER = 1 << 9; /** Only use oat files located in /system. Otherwise use dex/jar/apk . */ public static final int ONLY_USE_SYSTEM_OAT_FILES = 1 << 10; - /** Do enfore hidden API access restrictions. */ - public static final int ENABLE_HIDDEN_API_CHECKS = 1 << 11; /** Force generation of native debugging information for backtraces. */ - public static final int DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 12; + public static final int DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 11; + /** + * Hidden API access restrictions. This is a mask for bits representing the API enforcement + * policy, defined by {@code @ApplicationInfo.HiddenApiEnforcementPolicy}. + */ + public static final int API_ENFORCEMENT_POLICY_MASK = (1 << 12) | (1 << 13); + /** + * Bit shift for use with {@link #API_ENFORCEMENT_POLICY_MASK}. + * + * (flags & API_ENFORCEMENT_POLICY_MASK) >> API_ENFORCEMENT_POLICY_SHIFT gives + * @ApplicationInfo.ApiEnforcementPolicy values. + */ + public static final int API_ENFORCEMENT_POLICY_SHIFT = + Integer.numberOfTrailingZeros(API_ENFORCEMENT_POLICY_MASK); /** No external storage should be mounted. */ public static final int MOUNT_EXTERNAL_NONE = 0; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 8731cdad69c58..24f646ae96fcc 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -257,6 +257,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy; import android.content.pm.ConfigurationInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageManager; @@ -3944,12 +3945,14 @@ public class ActivityManagerService extends IActivityManager.Stub runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES; } - if (!app.info.isAllowedToUseHiddenApi() && - !disableHiddenApiChecks && - !mHiddenApiBlacklist.isDisabled()) { - // This app is not allowed to use undocumented and private APIs, or blacklisting is - // enabled. Set up its runtime with the appropriate flag. - runtimeFlags |= Zygote.ENABLE_HIDDEN_API_CHECKS; + if (!disableHiddenApiChecks && !mHiddenApiBlacklist.isDisabled()) { + @HiddenApiEnforcementPolicy int policy = + app.info.getHiddenApiEnforcementPolicy(); + int policyBits = (policy << Zygote.API_ENFORCEMENT_POLICY_SHIFT); + if ((policyBits & Zygote.API_ENFORCEMENT_POLICY_MASK) != policyBits) { + throw new IllegalStateException("Invalid API policy: " + policy); + } + runtimeFlags |= policyBits; } String invokeWith = null; diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 5ea778b838a7e..ae48844725226 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -47,6 +47,8 @@ import java.util.Map; import dalvik.system.DexFile; +import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_NONE; + import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE; import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE; import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED; @@ -532,7 +534,10 @@ public class PackageDexOptimizer { int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0; // Some apps are executed with restrictions on hidden API usage. If this app is one // of them, pass a flag to dexopt to enable the same restrictions during compilation. - int hiddenApiFlag = info.isAllowedToUseHiddenApi() ? 0 : DEXOPT_ENABLE_HIDDEN_API_CHECKS; + // TODO we should pass the actual flag value to dexopt, rather than assuming blacklist + int hiddenApiFlag = info.getHiddenApiEnforcementPolicy() == HIDDEN_API_ENFORCEMENT_NONE + ? 0 + : DEXOPT_ENABLE_HIDDEN_API_CHECKS; // Avoid generating CompactDex for modes that are latency critical. final int compilationReason = options.getCompilationReason(); boolean generateCompactDex = true;