diff options
| author | 2020-11-30 17:20:38 -0800 | |
|---|---|---|
| committer | 2020-12-07 15:25:21 -0800 | |
| commit | 0ef67ee5189747a147d3a63d2d160e9a4ec7c4c4 (patch) | |
| tree | 1896f84e3c041f1de7635bea5e41e9ac316db761 | |
| parent | d42204a8655a125fefbdfcd1c10646943d85df54 (diff) | |
Modify dexopt invocation based on install scenario
This CL implements the logic that modifies the way dexopt is invoked
based on the provided installation scenario.
Bug: 173137187
Test: build
Merged-In: Iab34d79cbbc4fb0d88946ef38a1edcca16cd3a29
Change-Id: Iab34d79cbbc4fb0d88946ef38a1edcca16cd3a29
5 files changed, 197 insertions, 25 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 498e7360bdd7..4630a905b41e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -677,10 +677,15 @@ public class PackageManagerService extends IPackageManager.Stub public static final int REASON_FIRST_BOOT = 0; public static final int REASON_BOOT = 1; public static final int REASON_INSTALL = 2; - public static final int REASON_BACKGROUND_DEXOPT = 3; - public static final int REASON_AB_OTA = 4; - public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 5; - public static final int REASON_SHARED = 6; + public static final int REASON_INSTALL_FAST = 3; + public static final int REASON_INSTALL_BULK = 4; + public static final int REASON_INSTALL_BULK_SECONDARY = 5; + public static final int REASON_INSTALL_BULK_DOWNGRADED = 6; + public static final int REASON_INSTALL_BULK_SECONDARY_DOWNGRADED = 7; + public static final int REASON_BACKGROUND_DEXOPT = 8; + public static final int REASON_AB_OTA = 9; + public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 10; + public static final int REASON_SHARED = 11; public static final int REASON_LAST = REASON_SHARED; @@ -16998,6 +17003,26 @@ public class PackageManagerService extends IPackageManager.Stub resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()), /* updateReferenceProfileContent= */ true); + // Compute the compilation reason from the installation scenario. + final int compilationReason = mDexManager.getCompilationReasonForInstallScenario( + reconciledPkg.installArgs.mInstallScenario); + + // Construct the DexoptOptions early to see if we should skip running dexopt. + // + // Do not run PackageDexOptimizer through the local performDexOpt + // method because `pkg` may not be in `mPackages` yet. + // + // Also, don't fail application installs if the dexopt step fails. + final boolean isBackupOrRestore = + reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_RESTORE + || reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_SETUP; + + final int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE + | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE + | (isBackupOrRestore ? DexoptOptions.DEXOPT_FOR_RESTORE : 0); + DexoptOptions dexoptOptions = + new DexoptOptions(packageName, compilationReason, dexoptFlags); + // Check whether we need to dexopt the app. // // NOTE: it is IMPORTANT to call dexopt: @@ -17018,11 +17043,18 @@ public class PackageManagerService extends IPackageManager.Stub // continuous progress to the useur instead of mysteriously blocking somewhere in the // middle of running an instant app. The default behaviour can be overridden // via gservices. + // + // Furthermore, dexopt may be skipped, depending on the install scenario and current + // state of the device. + // + // TODO(b/174695087): instantApp and onIncremental should be removed and their install + // path moved to SCENARIO_FAST. final boolean performDexopt = (!instantApp || Global.getInt(mContext.getContentResolver(), Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0) && !pkg.isDebuggable() - && (!onIncremental); + && (!onIncremental) + && dexoptOptions.isCompilationEnabled(); if (performDexopt) { // Compile the layout resources. @@ -17033,19 +17065,6 @@ public class PackageManagerService extends IPackageManager.Stub } Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); - // Do not run PackageDexOptimizer through the local performDexOpt - // method because `pkg` may not be in `mPackages` yet. - // - // Also, don't fail application installs if the dexopt step fails. - int flags = DexoptOptions.DEXOPT_BOOT_COMPLETE - | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE; - if (reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_RESTORE - || reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_SETUP) { - flags |= DexoptOptions.DEXOPT_FOR_RESTORE; - } - DexoptOptions dexoptOptions = new DexoptOptions(packageName, - REASON_INSTALL, - flags); ScanResult result = reconciledPkg.scanResult; // This mirrors logic from commitReconciledScanResultLocked, where the library files diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java index 5fc5bac0c8c2..9cd55a6bb07e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java @@ -18,6 +18,8 @@ package com.android.server.pm; import android.os.SystemProperties; +import com.android.server.pm.dex.DexoptOptions; + import dalvik.system.DexFile; /** @@ -26,10 +28,22 @@ import dalvik.system.DexFile; public class PackageManagerServiceCompilerMapping { // Names for compilation reasons. public static final String REASON_STRINGS[] = { - "first-boot", "boot", "install", "bg-dexopt", "ab-ota", "inactive", "shared" + "first-boot", + "boot", + "install", + "install-fast", + "install-bulk", + "install-bulk-secondary", + "install-bulk-downgraded", + "install-bulk-secondary-downgraded", + "bg-dexopt", + "ab-ota", + "inactive", + // "shared" must be the last entry + "shared" }; - static final int REASON_SHARED_INDEX = 6; + static final int REASON_SHARED_INDEX = REASON_STRINGS.length - 1; // Static block to ensure the strings array is of the right length. static { @@ -53,8 +67,9 @@ public class PackageManagerServiceCompilerMapping { // exception in case the reason or value are invalid. private static String getAndCheckValidity(int reason) { String sysPropValue = SystemProperties.get(getSystemPropertyName(reason)); - if (sysPropValue == null || sysPropValue.isEmpty() || - !DexFile.isValidCompilerFilter(sysPropValue)) { + if (sysPropValue == null || sysPropValue.isEmpty() + || !(sysPropValue.equals(DexoptOptions.COMPILER_FILTER_NOOP) + || DexFile.isValidCompilerFilter(sysPropValue))) { throw new IllegalStateException("Value \"" + sysPropValue +"\" not valid " + "(reason " + REASON_STRINGS[reason] + ")"); } else if (!isFilterAllowedForReason(reason, sysPropValue)) { diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java index a7f30fde703b..6e145b5ecbe4 100644 --- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java +++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java @@ -579,6 +579,8 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { // Constants used for logging compilation reason to TRON. // DO NOT CHANGE existing values. // + // In the below constants, the abbreviation DM stands for "DEX metadata". + // // NOTE: '-1' value is reserved for the case where we cannot produce a valid // PackageOptimizationInfo because the ArtManagerInternal is not ready to be used by the // ActivityMetricsLoggers. @@ -591,7 +593,18 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { private static final int TRON_COMPILATION_REASON_AB_OTA = 6; private static final int TRON_COMPILATION_REASON_INACTIVE = 7; private static final int TRON_COMPILATION_REASON_SHARED = 8; - private static final int TRON_COMPILATION_REASON_INSTALL_WITH_DEX_METADATA = 9; + private static final int TRON_COMPILATION_REASON_INSTALL_WITH_DM = 9; + private static final int TRON_COMPILATION_REASON_INSTALL_FAST = 10; + private static final int TRON_COMPILATION_REASON_INSTALL_BULK = 11; + private static final int TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY = 12; + private static final int TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED = 13; + private static final int TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED = 14; + private static final int TRON_COMPILATION_REASON_INSTALL_FAST_WITH_DM = 15; + private static final int TRON_COMPILATION_REASON_INSTALL_BULK_WITH_DM = 16; + private static final int TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_WITH_DM = 17; + private static final int TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED_WITH_DM = 18; + private static final int + TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED_WITH_DM = 19; // The annotation to add as a suffix to the compilation reason when dexopt was // performed with dex metadata. @@ -611,10 +624,30 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { case "ab-ota" : return TRON_COMPILATION_REASON_AB_OTA; case "inactive" : return TRON_COMPILATION_REASON_INACTIVE; case "shared" : return TRON_COMPILATION_REASON_SHARED; - // This is a special marker for dex metadata installation that does not + case "install-fast" : + return TRON_COMPILATION_REASON_INSTALL_FAST; + case "install-bulk" : + return TRON_COMPILATION_REASON_INSTALL_BULK; + case "install-bulk-secondary" : + return TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY; + case "install-bulk-downgraded" : + return TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED; + case "install-bulk-secondary-downgraded" : + return TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED; + // These are special markers for dex metadata installation that do not // have an equivalent as a system property. case "install" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION : - return TRON_COMPILATION_REASON_INSTALL_WITH_DEX_METADATA; + return TRON_COMPILATION_REASON_INSTALL_WITH_DM; + case "install-fast" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION : + return TRON_COMPILATION_REASON_INSTALL_FAST_WITH_DM; + case "install-bulk" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION : + return TRON_COMPILATION_REASON_INSTALL_BULK_WITH_DM; + case "install-bulk-secondary" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION : + return TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_WITH_DM; + case "install-bulk-downgraded" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION : + return TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED_WITH_DM; + case "install-bulk-secondary-downgraded" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION : + return TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED_WITH_DM; default: return TRON_COMPILATION_REASON_UNKNOWN; } } diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index 3074250950f7..cc6d80a2aeec 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -27,8 +27,11 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.content.pm.PackagePartitions; +import android.os.BatteryManager; import android.os.FileUtils; +import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; @@ -107,6 +110,13 @@ public class DexManager { @GuardedBy("mInstallLock") private final Installer mInstaller; + private BatteryManager mBatteryManager = null; + private PowerManager mPowerManager = null; + + // An integer percentage value used to determine when the device is considered to be on low + // power for compilation purposes. + private final int mCriticalBatteryLevel; + // Possible outcomes of a dex search. private static int DEX_SEARCH_NOT_FOUND = 0; // dex file not found private static int DEX_SEARCH_FOUND_PRIMARY = 1; // dex file is the primary/base apk @@ -123,6 +133,23 @@ public class DexManager { mInstaller = installer; mInstallLock = installLock; mDynamicCodeLogger = new DynamicCodeLogger(pms, installer); + + // This is currently checked to handle tests that pass in a null context. + // TODO(b/174783329): Modify the tests to pass in a mocked Context, PowerManager, + // and BatteryManager. + if (mContext != null) { + mPowerManager = mContext.getSystemService(PowerManager.class); + + if (mPowerManager == null) { + Slog.wtf(TAG, "Power Manager is unavailable at time of Dex Manager start"); + } + + mCriticalBatteryLevel = mContext.getResources().getInteger( + com.android.internal.R.integer.config_criticalBatteryWarningLevel); + } else { + // This value will never be used as the Battery Manager null check will fail first. + mCriticalBatteryLevel = 0; + } } public DynamicCodeLogger getDynamicCodeLogger() { @@ -905,6 +932,74 @@ public class DexManager { } } + /** + * Translates install scenarios into compilation reasons. This process can be influenced + * by the state of the device. + */ + public int getCompilationReasonForInstallScenario(int installScenario) { + // Compute the compilation reason from the installation scenario. + + boolean resourcesAreCritical = areBatteryThermalOrMemoryCritical(); + switch (installScenario) { + case PackageManager.INSTALL_SCENARIO_DEFAULT: { + return PackageManagerService.REASON_INSTALL; + } + case PackageManager.INSTALL_SCENARIO_FAST: { + return PackageManagerService.REASON_INSTALL_FAST; + } + case PackageManager.INSTALL_SCENARIO_BULK: { + if (resourcesAreCritical) { + return PackageManagerService.REASON_INSTALL_BULK_DOWNGRADED; + } else { + return PackageManagerService.REASON_INSTALL_BULK; + } + } + case PackageManager.INSTALL_SCENARIO_BULK_SECONDARY: { + if (resourcesAreCritical) { + return PackageManagerService.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED; + } else { + return PackageManagerService.REASON_INSTALL_BULK_SECONDARY; + } + } + default: { + throw new IllegalArgumentException("Invalid installation scenario"); + } + } + } + + /** + * Fetches the battery manager object and caches it if it hasn't been fetched already. + */ + private BatteryManager getBatteryManager() { + if (mBatteryManager == null) { + mBatteryManager = mContext.getSystemService(BatteryManager.class); + } + + return mBatteryManager; + } + + /** + * Returns true if the battery level, device temperature, or memory usage are considered to be + * in a critical state. + */ + private boolean areBatteryThermalOrMemoryCritical() { + BatteryManager batteryManager = getBatteryManager(); + boolean isBtmCritical = (batteryManager != null + && batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS) + == BatteryManager.BATTERY_STATUS_DISCHARGING + && batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) + <= mCriticalBatteryLevel) + || (mPowerManager != null + && mPowerManager.getCurrentThermalStatus() + >= PowerManager.THERMAL_STATUS_SEVERE); + + if (DEBUG) { + Log.d(TAG, "Battery, thermal, or memory are critical: " + isBtmCritical); + } + + return isBtmCritical; + } + public static class RegisterDexModuleResult { public RegisterDexModuleResult() { this(false, null); diff --git a/services/core/java/com/android/server/pm/dex/DexoptOptions.java b/services/core/java/com/android/server/pm/dex/DexoptOptions.java index 68f38861d7e4..ea233161b4af 100644 --- a/services/core/java/com/android/server/pm/dex/DexoptOptions.java +++ b/services/core/java/com/android/server/pm/dex/DexoptOptions.java @@ -65,6 +65,12 @@ public final class DexoptOptions { // or device setup and should be scheduled appropriately. public static final int DEXOPT_FOR_RESTORE = 1 << 11; // TODO(b/135202722): remove + /** + * A value indicating that dexopt shouldn't be run. This string is only used when loading + * filters from the `pm.dexopt.install*` properties and is not propagated to dex2oat. + */ + public static final String COMPILER_FILTER_NOOP = "skip"; + // The name of package to optimize. private final String mPackageName; @@ -176,6 +182,10 @@ public final class DexoptOptions { return mCompilationReason; } + public boolean isCompilationEnabled() { + return !mCompilerFilter.equals(COMPILER_FILTER_NOOP); + } + /** * Creates a new set of DexoptOptions which are the same with the exception of the compiler * filter (set to the given value). |