From d42204a8655a125fefbdfcd1c10646943d85df54 Mon Sep 17 00:00:00 2001 From: Chris Wailes Date: Tue, 20 Oct 2020 00:03:48 -0700 Subject: [PATCH 1/2] Adds an "install scenario" field to the appropriate datastructures This CL adds an "install scenario" field to several data structures used by the Package Manager. This value will be used by a following CL to adjust the invocation of dexopt based on the indicated use case. Bug: 173137187 Test: build Merged-In: I1d0df8edf85a598905a5e7509f6c811df5c20e2e Change-Id: I1d0df8edf85a598905a5e7509f6c811df5c20e2e --- .../android/content/pm/PackageInstaller.java | 18 +++++++ .../android/content/pm/PackageManager.java | 54 +++++++++++++++++++ .../server/pm/PackageInstallerSession.java | 1 + .../server/pm/PackageManagerService.java | 13 +++-- 4 files changed, 82 insertions(+), 4 deletions(-) diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 47f84c823fc4d..db579128b2387 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -37,6 +37,7 @@ import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager.DeleteFlags; import android.content.pm.PackageManager.InstallReason; +import android.content.pm.PackageManager.InstallScenario; import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; @@ -1466,6 +1467,14 @@ public class PackageInstaller { public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY; /** {@hide} */ public @InstallReason int installReason = PackageManager.INSTALL_REASON_UNKNOWN; + /** + * {@hide} + * + * This flag indicates which installation scenario best describes this session. The system + * may use this value when making decisions about how to handle the installation, such as + * prioritizing system health or user experience. + */ + public @InstallScenario int installScenario = PackageManager.INSTALL_SCENARIO_DEFAULT; /** {@hide} */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long sizeBytes = -1; @@ -1529,6 +1538,7 @@ public class PackageInstaller { installFlags = source.readInt(); installLocation = source.readInt(); installReason = source.readInt(); + installScenario = source.readInt(); sizeBytes = source.readLong(); appPackageName = source.readString(); appIcon = source.readParcelable(null); @@ -1560,6 +1570,7 @@ public class PackageInstaller { ret.installFlags = installFlags; ret.installLocation = installLocation; ret.installReason = installReason; + ret.installScenario = installScenario; ret.sizeBytes = sizeBytes; ret.appPackageName = appPackageName; ret.appIcon = appIcon; // not a copy. @@ -1985,6 +1996,8 @@ public class PackageInstaller { pw.printPair("mode", mode); pw.printHexPair("installFlags", installFlags); pw.printPair("installLocation", installLocation); + pw.printPair("installReason", installReason); + pw.printPair("installScenario", installScenario); pw.printPair("sizeBytes", sizeBytes); pw.printPair("appPackageName", appPackageName); pw.printPair("appIcon", (appIcon != null)); @@ -2018,6 +2031,7 @@ public class PackageInstaller { dest.writeInt(installFlags); dest.writeInt(installLocation); dest.writeInt(installReason); + dest.writeInt(installScenario); dest.writeLong(sizeBytes); dest.writeString(appPackageName); dest.writeParcelable(appIcon, flags); @@ -2127,6 +2141,8 @@ public class PackageInstaller { /** {@hide} */ public @InstallReason int installReason; /** {@hide} */ + public @InstallReason int installScenario; + /** {@hide} */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public long sizeBytes; /** {@hide} */ @@ -2204,6 +2220,7 @@ public class PackageInstaller { mode = source.readInt(); installReason = source.readInt(); + installScenario = source.readInt(); sizeBytes = source.readLong(); appPackageName = source.readString(); appIcon = source.readParcelable(null); @@ -2734,6 +2751,7 @@ public class PackageInstaller { dest.writeInt(mode); dest.writeInt(installReason); + dest.writeInt(installScenario); dest.writeLong(sizeBytes); dest.writeString(appPackageName); dest.writeParcelable(appIcon, flags); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 50ef08a9598ad..ae1067d8d82d4 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1037,6 +1037,60 @@ public abstract class PackageManager { */ public static final int INSTALL_REASON_ROLLBACK = 5; + /** @hide */ + @IntDef(prefix = { "INSTALL_SCENARIO_" }, value = { + INSTALL_SCENARIO_DEFAULT, + INSTALL_SCENARIO_FAST, + INSTALL_SCENARIO_BULK, + INSTALL_SCENARIO_BULK_SECONDARY, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface InstallScenario {} + + /** + * A value to indicate the lack of CUJ information, disabling all installation scenario logic. + * + * @hide + */ + public static final int INSTALL_SCENARIO_DEFAULT = 0; + + /** + * Installation scenario providing the fastest “install button to launch" experience possible. + * + * @hide + */ + public static final int INSTALL_SCENARIO_FAST = 1; + + /** + * Installation scenario indicating a bulk operation with the desired result of a fully + * optimized application. If the system is busy or resources are scarce the system will + * perform less work to avoid impacting system health. + * + * Examples of bulk installation scenarios might include device restore, background updates of + * multiple applications, or user-triggered updates for all applications. + * + * The decision to use BULK or BULK_SECONDARY should be based on the desired user experience. + * BULK_SECONDARY operations may take less time to complete but, when they do, will produce + * less optimized applications. The device state (e.g. memory usage or battery status) should + * not be considered when making this decision as those factors are taken into account by the + * Package Manager when acting on the installation scenario. + * + * @hide + */ + public static final int INSTALL_SCENARIO_BULK = 2; + + /** + * Installation scenario indicating a bulk operation that prioritizes minimal system health + * impact over application optimization. The application may undergo additional optimization + * if the system is idle and system resources are abundant. The more elements of a bulk + * operation that are marked BULK_SECONDARY, the faster the entire bulk operation will be. + * + * See the comments for INSTALL_SCENARIO_BULK for more information. + * + * @hide + */ + public static final int INSTALL_SCENARIO_BULK_SECONDARY = 3; + /** @hide */ @IntDef(prefix = { "UNINSTALL_REASON_" }, value = { UNINSTALL_REASON_UNKNOWN, diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 90d9834d891a5..8c2a6e7a0e8d3 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -665,6 +665,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { info.mode = params.mode; info.installReason = params.installReason; + info.installScenario = params.installScenario; info.sizeBytes = params.sizeBytes; info.appPackageName = params.appPackageName; if (includeIcon) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 7fa322559d465..498e7360bdd7a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -14853,6 +14853,7 @@ public class PackageManagerService extends IPackageManager.Stub final VerificationInfo verificationInfo; final PackageParser.SigningDetails signingDetails; final int installReason; + final int mInstallScenario; @Nullable MultiPackageInstallParams mParentInstallParams; final long requiredInstalledVersionCode; @@ -14881,6 +14882,7 @@ public class PackageManagerService extends IPackageManager.Stub this.autoRevokePermissionsMode = autoRevokePermissionsMode; this.signingDetails = signingDetails; this.installReason = installReason; + this.mInstallScenario = PackageManager.INSTALL_SCENARIO_DEFAULT; this.requiredInstalledVersionCode = requiredInstalledVersionCode; this.forceQueryableOverride = false; this.mDataLoaderType = dataLoaderType; @@ -14908,6 +14910,7 @@ public class PackageManagerService extends IPackageManager.Stub activeInstallSession.getInstallSource().installerPackageName, activeInstallSession.getInstallerUid(), sessionParams.installReason); + mInstallScenario = sessionParams.installScenario; observer = activeInstallSession.getObserver(); installFlags = sessionParams.installFlags; installSource = activeInstallSession.getInstallSource(); @@ -15545,6 +15548,7 @@ public class PackageManagerService extends IPackageManager.Stub final int traceCookie; final PackageParser.SigningDetails signingDetails; final int installReason; + final int mInstallScenario; final boolean forceQueryableOverride; @Nullable final MultiPackageInstallParams mMultiPackageInstallParams; final int mDataLoaderType; @@ -15561,7 +15565,7 @@ public class PackageManagerService extends IPackageManager.Stub List whitelistedRestrictedPermissions, int autoRevokePermissionsMode, String traceMethod, int traceCookie, SigningDetails signingDetails, - int installReason, boolean forceQueryableOverride, + int installReason, int installScenario, boolean forceQueryableOverride, MultiPackageInstallParams multiPackageInstallParams, int dataLoaderType) { this.origin = origin; this.move = move; @@ -15579,6 +15583,7 @@ public class PackageManagerService extends IPackageManager.Stub this.traceCookie = traceCookie; this.signingDetails = signingDetails; this.installReason = installReason; + this.mInstallScenario = installScenario; this.forceQueryableOverride = forceQueryableOverride; this.mMultiPackageInstallParams = multiPackageInstallParams; this.mDataLoaderType = dataLoaderType; @@ -15592,7 +15597,7 @@ public class PackageManagerService extends IPackageManager.Stub params.grantedRuntimePermissions, params.whitelistedRestrictedPermissions, params.autoRevokePermissionsMode, params.traceMethod, params.traceCookie, params.signingDetails, - params.installReason, params.forceQueryableOverride, + params.installReason, params.mInstallScenario, params.forceQueryableOverride, params.mParentInstallParams, params.mDataLoaderType); } @@ -15684,8 +15689,8 @@ public class PackageManagerService extends IPackageManager.Stub super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY, null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0, PackageParser.SigningDetails.UNKNOWN, - PackageManager.INSTALL_REASON_UNKNOWN, false, null /* parent */, - DataLoaderType.NONE); + PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.INSTALL_SCENARIO_DEFAULT, + false, null /* parent */, DataLoaderType.NONE); this.codeFile = (codePath != null) ? new File(codePath) : null; this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null; } From 0ef67ee5189747a147d3a63d2d160e9a4ec7c4c4 Mon Sep 17 00:00:00 2001 From: Chris Wailes Date: Mon, 30 Nov 2020 17:20:38 -0800 Subject: [PATCH 2/2] 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 --- .../server/pm/PackageManagerService.java | 55 +++++++---- .../PackageManagerServiceCompilerMapping.java | 23 ++++- .../server/pm/dex/ArtManagerService.java | 39 +++++++- .../com/android/server/pm/dex/DexManager.java | 95 +++++++++++++++++++ .../android/server/pm/dex/DexoptOptions.java | 10 ++ 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 498e7360bdd7a..4630a905b41ee 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 5fc5bac0c8c2d..9cd55a6bb07e8 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 a7f30fde703bc..6e145b5ecbe40 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 3074250950f75..cc6d80a2aeec9 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 68f38861d7e46..ea233161b4afb 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).