Loading services/core/java/com/android/server/pm/BackgroundDexOptService.java +106 −86 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.pm; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import static com.android.server.pm.dex.ArtStatsLogUtils.BackgroundDexoptJobStatsLogger; import android.annotation.IntDef; import android.annotation.NonNull; Loading Loading @@ -77,37 +78,37 @@ public final class BackgroundDexOptService { private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @VisibleForTesting static final int JOB_IDLE_OPTIMIZE = 800; @VisibleForTesting static final int JOB_POST_BOOT_UPDATE = 801; @VisibleForTesting static final int JOB_IDLE_OPTIMIZE = 800; @VisibleForTesting static final int JOB_POST_BOOT_UPDATE = 801; private static final long IDLE_OPTIMIZATION_PERIOD = TimeUnit.DAYS.toMillis(1); private static final long CANCELLATION_WAIT_CHECK_INTERVAL_MS = 200; private static ComponentName sDexoptServiceName = new ComponentName("android", BackgroundDexOptJobService.class.getName()); private static ComponentName sDexoptServiceName = new ComponentName("android", BackgroundDexOptJobService.class.getName()); // Possible return codes of individual optimization steps. /** Ok status: Optimizations finished, All packages were processed, can continue */ /* package */ static final int STATUS_OK = 0; public static final int STATUS_OK = 0; /** Optimizations should be aborted. Job scheduler requested it. */ /* package */ static final int STATUS_ABORT_BY_CANCELLATION = 1; public static final int STATUS_ABORT_BY_CANCELLATION = 1; /** Optimizations should be aborted. No space left on device. */ /* package */ static final int STATUS_ABORT_NO_SPACE_LEFT = 2; public static final int STATUS_ABORT_NO_SPACE_LEFT = 2; /** Optimizations should be aborted. Thermal throttling level too high. */ /* package */ static final int STATUS_ABORT_THERMAL = 3; public static final int STATUS_ABORT_THERMAL = 3; /** Battery level too low */ /* package */ static final int STATUS_ABORT_BATTERY = 4; public static final int STATUS_ABORT_BATTERY = 4; /** * {@link PackageDexOptimizer#DEX_OPT_FAILED} case. This state means some packages have failed * compilation during the job. Note that the failure will not be permanent as the next dexopt * job will exclude those failed packages. */ /* package */ static final int STATUS_DEX_OPT_FAILED = 5; public static final int STATUS_DEX_OPT_FAILED = 5; @IntDef(prefix = {"STATUS_"}, value = { @IntDef(prefix = {"STATUS_"}, value = { STATUS_OK, STATUS_ABORT_BY_CANCELLATION, STATUS_ABORT_NO_SPACE_LEFT, Loading @@ -116,8 +117,7 @@ public final class BackgroundDexOptService { STATUS_DEX_OPT_FAILED, }) @Retention(RetentionPolicy.SOURCE) private @interface Status { } public @interface Status {} // Used for calculating space threshold for downgrading unused apps. private static final int LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE = 2; Loading @@ -129,33 +129,30 @@ public final class BackgroundDexOptService { private final DexOptHelper mDexOptHelper; private final BackgroundDexoptJobStatsLogger mStatsLogger = new BackgroundDexoptJobStatsLogger(); private final Object mLock = new Object(); // Thread currently running dexopt. This will be null if dexopt is not running. // The thread running dexopt make sure to set this into null when the pending dexopt is // completed. @GuardedBy("mLock") @Nullable private Thread mDexOptThread; @GuardedBy("mLock") @Nullable private Thread mDexOptThread; // Thread currently cancelling dexopt. This thread is in blocked wait state until // cancellation is done. Only this thread can change states for control. The other threads, if // need to wait for cancellation, should just wait without doing any control. @GuardedBy("mLock") @Nullable private Thread mDexOptCancellingThread; @GuardedBy("mLock") @Nullable private Thread mDexOptCancellingThread; // Tells whether post boot update is completed or not. @GuardedBy("mLock") private boolean mFinishedPostBootUpdate; @GuardedBy("mLock") private boolean mFinishedPostBootUpdate; @GuardedBy("mLock") @Status private int mLastExecutionStatus = STATUS_OK; @GuardedBy("mLock") @Status private int mLastExecutionStatus = STATUS_OK; @GuardedBy("mLock") private long mLastExecutionStartTimeMs; @GuardedBy("mLock") private long mLastExecutionDurationMs; @GuardedBy("mLock") private long mLastExecutionStartTimeMs; @GuardedBy("mLock") private long mLastExecutionDurationIncludingSleepMs; @GuardedBy("mLock") private long mLastExecutionStartUptimeMs; @GuardedBy("mLock") private long mLastExecutionDurationMs; // Keeps packages cancelled from PDO for last session. This is for debugging. @GuardedBy("mLock") Loading @@ -181,8 +178,8 @@ public final class BackgroundDexOptService { void onPackagesUpdated(ArraySet<String> updatedPackages); } public BackgroundDexOptService(Context context, DexManager dexManager, PackageManagerService pm) { public BackgroundDexOptService( Context context, DexManager dexManager, PackageManagerService pm) { this(new Injector(context, dexManager, pm)); } Loading Loading @@ -234,6 +231,10 @@ public final class BackgroundDexOptService { writer.println(mLastExecutionStatus); writer.print("mLastExecutionStartTimeMs:"); writer.println(mLastExecutionStartTimeMs); writer.print("mLastExecutionDurationIncludingSleepMs:"); writer.println(mLastExecutionDurationIncludingSleepMs); writer.print("mLastExecutionStartUptimeMs:"); writer.println(mLastExecutionStartUptimeMs); writer.print("mLastExecutionDurationMs:"); writer.println(mLastExecutionDurationMs); writer.print("now:"); Loading Loading @@ -361,18 +362,21 @@ public final class BackgroundDexOptService { resetStatesForNewDexOptRunLocked(mInjector.createAndStartThread( "BackgroundDexOptService_" + (isPostBootUpdateJob ? "PostBoot" : "Idle"), () -> { TimingsTraceAndSlog tr = new TimingsTraceAndSlog(TAG, Trace.TRACE_TAG_PACKAGE_MANAGER); TimingsTraceAndSlog tr = new TimingsTraceAndSlog(TAG, Trace.TRACE_TAG_PACKAGE_MANAGER); tr.traceBegin("jobExecution"); boolean completed = false; try { completed = runIdleOptimization(pm, pkgs, params.getJobId() == JOB_POST_BOOT_UPDATE); completed = runIdleOptimization( pm, pkgs, params.getJobId() == JOB_POST_BOOT_UPDATE); } finally { // Those cleanup should be done always. tr.traceEnd(); Slog.i(TAG, "dexopt finishing. jobid:" + params.getJobId() Slog.i(TAG, "dexopt finishing. jobid:" + params.getJobId() + " completed:" + completed); writeStatsLog(params); if (params.getJobId() == JOB_POST_BOOT_UPDATE) { if (completed) { markPostBootUpdateCompleted(params); Loading Loading @@ -485,11 +489,10 @@ public final class BackgroundDexOptService { private void scheduleAJob(int jobId) { JobScheduler js = mInjector.getJobScheduler(); JobInfo.Builder builder = new JobInfo.Builder(jobId, sDexoptServiceName) .setRequiresDeviceIdle(true); JobInfo.Builder builder = new JobInfo.Builder(jobId, sDexoptServiceName).setRequiresDeviceIdle(true); if (jobId == JOB_IDLE_OPTIMIZE) { builder.setRequiresCharging(true) .setPeriodic(IDLE_OPTIMIZATION_PERIOD); builder.setRequiresCharging(true).setPeriodic(IDLE_OPTIMIZATION_PERIOD); } js.schedule(builder.build()); } Loading Loading @@ -533,19 +536,22 @@ public final class BackgroundDexOptService { * Returns whether we've successfully run the job. Note that it will return true even if some * packages may have failed compiling. */ private boolean runIdleOptimization(PackageManagerService pm, List<String> pkgs, boolean isPostBootUpdate) { private boolean runIdleOptimization( PackageManagerService pm, List<String> pkgs, boolean isPostBootUpdate) { synchronized (mLock) { mLastExecutionStartTimeMs = SystemClock.elapsedRealtime(); mLastExecutionDurationIncludingSleepMs = -1; mLastExecutionStartUptimeMs = SystemClock.uptimeMillis(); mLastExecutionDurationMs = -1; } long lowStorageThreshold = getLowStorageThreshold(); int status = idleOptimizePackages(pm, pkgs, lowStorageThreshold, isPostBootUpdate); int status = idleOptimizePackages(pm, pkgs, lowStorageThreshold, isPostBootUpdate); logStatus(status); synchronized (mLock) { mLastExecutionStatus = status; mLastExecutionDurationMs = SystemClock.elapsedRealtime() - mLastExecutionStartTimeMs; mLastExecutionDurationIncludingSleepMs = SystemClock.elapsedRealtime() - mLastExecutionStartTimeMs; mLastExecutionDurationMs = SystemClock.uptimeMillis() - mLastExecutionStartUptimeMs; } return status == STATUS_OK || status == STATUS_DEX_OPT_FAILED; Loading Loading @@ -606,8 +612,8 @@ public final class BackgroundDexOptService { // Only downgrade apps when space is low on device. // Threshold is selected above the lowStorageThreshold so that we can pro-actively clean // up disk before user hits the actual lowStorageThreshold. long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE * lowStorageThreshold; long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE * lowStorageThreshold; boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade); if (DEBUG) { Slog.d(TAG, "Should Downgrade " + shouldDowngrade); Loading @@ -627,13 +633,14 @@ public final class BackgroundDexOptService { // Should be aborted by the scheduler. return abortCode; } @DexOptResult int downgradeResult = downgradePackage(snapshot, pm, pkg, @DexOptResult int downgradeResult = downgradePackage(snapshot, pm, pkg, /* isForPrimaryDex= */ true, isPostBootUpdate); if (downgradeResult == PackageDexOptimizer.DEX_OPT_PERFORMED) { updatedPackages.add(pkg); } @Status int status = convertPackageDexOptimizerStatusToInternal( downgradeResult); @Status int status = convertPackageDexOptimizerStatusToInternal(downgradeResult); if (status != STATUS_OK) { return status; } Loading Loading @@ -680,8 +687,8 @@ public final class BackgroundDexOptService { return abortCode; } @DexOptResult int primaryResult = optimizePackage(pkg, true /* isForPrimaryDex */, isPostBootUpdate); @DexOptResult int primaryResult = optimizePackage(pkg, true /* isForPrimaryDex */, isPostBootUpdate); if (primaryResult == PackageDexOptimizer.DEX_OPT_CANCELLED) { return STATUS_ABORT_BY_CANCELLATION; } Loading @@ -695,7 +702,8 @@ public final class BackgroundDexOptService { continue; } @DexOptResult int secondaryResult = @DexOptResult int secondaryResult = optimizePackage(pkg, false /* isForPrimaryDex */, isPostBootUpdate); if (secondaryResult == PackageDexOptimizer.DEX_OPT_CANCELLED) { return STATUS_ABORT_BY_CANCELLATION; Loading Loading @@ -794,22 +802,21 @@ public final class BackgroundDexOptService { } @DexOptResult private int performDexOptPrimary(String pkg, int reason, int dexoptFlags) { private int performDexOptPrimary(String pkg, int reason, int dexoptFlags) { DexoptOptions dexoptOptions = new DexoptOptions(pkg, reason, dexoptFlags); return trackPerformDexOpt(pkg, /*isForPrimaryDex=*/true, () -> mDexOptHelper.performDexOptWithStatus(dexoptOptions)); } @DexOptResult private int performDexOptSecondary(String pkg, int reason, int dexoptFlags) { DexoptOptions dexoptOptions = new DexoptOptions(pkg, reason, dexoptFlags | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX); private int performDexOptSecondary(String pkg, int reason, int dexoptFlags) { DexoptOptions dexoptOptions = new DexoptOptions( pkg, reason, dexoptFlags | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX); return trackPerformDexOpt(pkg, /*isForPrimaryDex=*/false, () -> mDexOptHelper.performDexOpt(dexoptOptions) ? PackageDexOptimizer.DEX_OPT_PERFORMED : PackageDexOptimizer.DEX_OPT_FAILED ); () -> mDexOptHelper.performDexOpt(dexoptOptions) ? PackageDexOptimizer.DEX_OPT_PERFORMED : PackageDexOptimizer.DEX_OPT_FAILED); } /** Loading @@ -822,8 +829,8 @@ public final class BackgroundDexOptService { * {@link PackageDexOptimizer#DEX_OPT_FAILED} */ @DexOptResult private int trackPerformDexOpt(String pkg, boolean isForPrimaryDex, Supplier<Integer> performDexOptWrapper) { private int trackPerformDexOpt( String pkg, boolean isForPrimaryDex, Supplier<Integer> performDexOptWrapper) { ArraySet<String> failedPackageNames; synchronized (mLock) { failedPackageNames = Loading Loading @@ -940,6 +947,19 @@ public final class BackgroundDexOptService { } } private void writeStatsLog(JobParameters params) { @Status int status; long durationMs; long durationIncludingSleepMs; synchronized (mLock) { status = mLastExecutionStatus; durationMs = mLastExecutionDurationMs; durationIncludingSleepMs = mLastExecutionDurationIncludingSleepMs; } mStatsLogger.write(status, params.getStopReason(), durationMs, durationIncludingSleepMs); } /** Injector pattern for testing purpose */ @VisibleForTesting static final class Injector { Loading Loading @@ -979,8 +999,8 @@ public final class BackgroundDexOptService { } boolean isBackgroundDexOptDisabled() { return SystemProperties.getBoolean("pm.dexopt.disable_bg_dexopt" /* key */, false /* default */); return SystemProperties.getBoolean( "pm.dexopt.disable_bg_dexopt" /* key */, false /* default */); } boolean isBatteryLevelLow() { Loading Loading @@ -1010,8 +1030,8 @@ public final class BackgroundDexOptService { } int getCurrentThermalStatus() { IThermalService thermalService = IThermalService.Stub .asInterface(ServiceManager.getService(Context.THERMAL_SERVICE)); IThermalService thermalService = IThermalService.Stub.asInterface( ServiceManager.getService(Context.THERMAL_SERVICE)); try { return thermalService.getCurrentThermalStatus(); } catch (RemoteException e) { Loading @@ -1020,8 +1040,8 @@ public final class BackgroundDexOptService { } int getDexOptThermalCutoff() { return SystemProperties.getInt("dalvik.vm.dexopt.thermal-cutoff", THERMAL_CUTOFF_DEFAULT); return SystemProperties.getInt( "dalvik.vm.dexopt.thermal-cutoff", THERMAL_CUTOFF_DEFAULT); } Thread createAndStartThread(String name, Runnable target) { Loading services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java +29 −0 Original line number Diff line number Diff line Loading @@ -22,11 +22,13 @@ import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATI import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK; import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK; import android.app.job.JobParameters; import android.os.SystemClock; import android.util.Slog; import android.util.jar.StrictJarFile; import com.android.internal.art.ArtStatsLog; import com.android.server.pm.BackgroundDexOptService; import com.android.server.pm.PackageManagerService; import java.io.IOException; Loading Loading @@ -299,4 +301,31 @@ public class ArtStatsLogUtils { ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_UNKNOWN)); } } private static final Map<Integer, Integer> STATUS_MAP = Map.of(BackgroundDexOptService.STATUS_OK, ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_JOB_FINISHED, BackgroundDexOptService.STATUS_ABORT_BY_CANCELLATION, ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_BY_CANCELLATION, BackgroundDexOptService.STATUS_ABORT_NO_SPACE_LEFT, ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_NO_SPACE_LEFT, BackgroundDexOptService.STATUS_ABORT_THERMAL, ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_THERMAL, BackgroundDexOptService.STATUS_ABORT_BATTERY, ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_BATTERY, BackgroundDexOptService.STATUS_DEX_OPT_FAILED, ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_JOB_FINISHED); /** Helper class to write background dexopt job stats to statsd. */ public static class BackgroundDexoptJobStatsLogger { /** Writes background dexopt job stats to statsd. */ public void write(@BackgroundDexOptService.Status int status, @JobParameters.StopReason int cancellationReason, long durationMs, long durationIncludingSleepMs) { ArtStatsLog.write(ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED, STATUS_MAP.getOrDefault(status, ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_UNKNOWN), cancellationReason, durationMs, durationIncludingSleepMs); } } } Loading
services/core/java/com/android/server/pm/BackgroundDexOptService.java +106 −86 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.pm; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import static com.android.server.pm.dex.ArtStatsLogUtils.BackgroundDexoptJobStatsLogger; import android.annotation.IntDef; import android.annotation.NonNull; Loading Loading @@ -77,37 +78,37 @@ public final class BackgroundDexOptService { private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @VisibleForTesting static final int JOB_IDLE_OPTIMIZE = 800; @VisibleForTesting static final int JOB_POST_BOOT_UPDATE = 801; @VisibleForTesting static final int JOB_IDLE_OPTIMIZE = 800; @VisibleForTesting static final int JOB_POST_BOOT_UPDATE = 801; private static final long IDLE_OPTIMIZATION_PERIOD = TimeUnit.DAYS.toMillis(1); private static final long CANCELLATION_WAIT_CHECK_INTERVAL_MS = 200; private static ComponentName sDexoptServiceName = new ComponentName("android", BackgroundDexOptJobService.class.getName()); private static ComponentName sDexoptServiceName = new ComponentName("android", BackgroundDexOptJobService.class.getName()); // Possible return codes of individual optimization steps. /** Ok status: Optimizations finished, All packages were processed, can continue */ /* package */ static final int STATUS_OK = 0; public static final int STATUS_OK = 0; /** Optimizations should be aborted. Job scheduler requested it. */ /* package */ static final int STATUS_ABORT_BY_CANCELLATION = 1; public static final int STATUS_ABORT_BY_CANCELLATION = 1; /** Optimizations should be aborted. No space left on device. */ /* package */ static final int STATUS_ABORT_NO_SPACE_LEFT = 2; public static final int STATUS_ABORT_NO_SPACE_LEFT = 2; /** Optimizations should be aborted. Thermal throttling level too high. */ /* package */ static final int STATUS_ABORT_THERMAL = 3; public static final int STATUS_ABORT_THERMAL = 3; /** Battery level too low */ /* package */ static final int STATUS_ABORT_BATTERY = 4; public static final int STATUS_ABORT_BATTERY = 4; /** * {@link PackageDexOptimizer#DEX_OPT_FAILED} case. This state means some packages have failed * compilation during the job. Note that the failure will not be permanent as the next dexopt * job will exclude those failed packages. */ /* package */ static final int STATUS_DEX_OPT_FAILED = 5; public static final int STATUS_DEX_OPT_FAILED = 5; @IntDef(prefix = {"STATUS_"}, value = { @IntDef(prefix = {"STATUS_"}, value = { STATUS_OK, STATUS_ABORT_BY_CANCELLATION, STATUS_ABORT_NO_SPACE_LEFT, Loading @@ -116,8 +117,7 @@ public final class BackgroundDexOptService { STATUS_DEX_OPT_FAILED, }) @Retention(RetentionPolicy.SOURCE) private @interface Status { } public @interface Status {} // Used for calculating space threshold for downgrading unused apps. private static final int LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE = 2; Loading @@ -129,33 +129,30 @@ public final class BackgroundDexOptService { private final DexOptHelper mDexOptHelper; private final BackgroundDexoptJobStatsLogger mStatsLogger = new BackgroundDexoptJobStatsLogger(); private final Object mLock = new Object(); // Thread currently running dexopt. This will be null if dexopt is not running. // The thread running dexopt make sure to set this into null when the pending dexopt is // completed. @GuardedBy("mLock") @Nullable private Thread mDexOptThread; @GuardedBy("mLock") @Nullable private Thread mDexOptThread; // Thread currently cancelling dexopt. This thread is in blocked wait state until // cancellation is done. Only this thread can change states for control. The other threads, if // need to wait for cancellation, should just wait without doing any control. @GuardedBy("mLock") @Nullable private Thread mDexOptCancellingThread; @GuardedBy("mLock") @Nullable private Thread mDexOptCancellingThread; // Tells whether post boot update is completed or not. @GuardedBy("mLock") private boolean mFinishedPostBootUpdate; @GuardedBy("mLock") private boolean mFinishedPostBootUpdate; @GuardedBy("mLock") @Status private int mLastExecutionStatus = STATUS_OK; @GuardedBy("mLock") @Status private int mLastExecutionStatus = STATUS_OK; @GuardedBy("mLock") private long mLastExecutionStartTimeMs; @GuardedBy("mLock") private long mLastExecutionDurationMs; @GuardedBy("mLock") private long mLastExecutionStartTimeMs; @GuardedBy("mLock") private long mLastExecutionDurationIncludingSleepMs; @GuardedBy("mLock") private long mLastExecutionStartUptimeMs; @GuardedBy("mLock") private long mLastExecutionDurationMs; // Keeps packages cancelled from PDO for last session. This is for debugging. @GuardedBy("mLock") Loading @@ -181,8 +178,8 @@ public final class BackgroundDexOptService { void onPackagesUpdated(ArraySet<String> updatedPackages); } public BackgroundDexOptService(Context context, DexManager dexManager, PackageManagerService pm) { public BackgroundDexOptService( Context context, DexManager dexManager, PackageManagerService pm) { this(new Injector(context, dexManager, pm)); } Loading Loading @@ -234,6 +231,10 @@ public final class BackgroundDexOptService { writer.println(mLastExecutionStatus); writer.print("mLastExecutionStartTimeMs:"); writer.println(mLastExecutionStartTimeMs); writer.print("mLastExecutionDurationIncludingSleepMs:"); writer.println(mLastExecutionDurationIncludingSleepMs); writer.print("mLastExecutionStartUptimeMs:"); writer.println(mLastExecutionStartUptimeMs); writer.print("mLastExecutionDurationMs:"); writer.println(mLastExecutionDurationMs); writer.print("now:"); Loading Loading @@ -361,18 +362,21 @@ public final class BackgroundDexOptService { resetStatesForNewDexOptRunLocked(mInjector.createAndStartThread( "BackgroundDexOptService_" + (isPostBootUpdateJob ? "PostBoot" : "Idle"), () -> { TimingsTraceAndSlog tr = new TimingsTraceAndSlog(TAG, Trace.TRACE_TAG_PACKAGE_MANAGER); TimingsTraceAndSlog tr = new TimingsTraceAndSlog(TAG, Trace.TRACE_TAG_PACKAGE_MANAGER); tr.traceBegin("jobExecution"); boolean completed = false; try { completed = runIdleOptimization(pm, pkgs, params.getJobId() == JOB_POST_BOOT_UPDATE); completed = runIdleOptimization( pm, pkgs, params.getJobId() == JOB_POST_BOOT_UPDATE); } finally { // Those cleanup should be done always. tr.traceEnd(); Slog.i(TAG, "dexopt finishing. jobid:" + params.getJobId() Slog.i(TAG, "dexopt finishing. jobid:" + params.getJobId() + " completed:" + completed); writeStatsLog(params); if (params.getJobId() == JOB_POST_BOOT_UPDATE) { if (completed) { markPostBootUpdateCompleted(params); Loading Loading @@ -485,11 +489,10 @@ public final class BackgroundDexOptService { private void scheduleAJob(int jobId) { JobScheduler js = mInjector.getJobScheduler(); JobInfo.Builder builder = new JobInfo.Builder(jobId, sDexoptServiceName) .setRequiresDeviceIdle(true); JobInfo.Builder builder = new JobInfo.Builder(jobId, sDexoptServiceName).setRequiresDeviceIdle(true); if (jobId == JOB_IDLE_OPTIMIZE) { builder.setRequiresCharging(true) .setPeriodic(IDLE_OPTIMIZATION_PERIOD); builder.setRequiresCharging(true).setPeriodic(IDLE_OPTIMIZATION_PERIOD); } js.schedule(builder.build()); } Loading Loading @@ -533,19 +536,22 @@ public final class BackgroundDexOptService { * Returns whether we've successfully run the job. Note that it will return true even if some * packages may have failed compiling. */ private boolean runIdleOptimization(PackageManagerService pm, List<String> pkgs, boolean isPostBootUpdate) { private boolean runIdleOptimization( PackageManagerService pm, List<String> pkgs, boolean isPostBootUpdate) { synchronized (mLock) { mLastExecutionStartTimeMs = SystemClock.elapsedRealtime(); mLastExecutionDurationIncludingSleepMs = -1; mLastExecutionStartUptimeMs = SystemClock.uptimeMillis(); mLastExecutionDurationMs = -1; } long lowStorageThreshold = getLowStorageThreshold(); int status = idleOptimizePackages(pm, pkgs, lowStorageThreshold, isPostBootUpdate); int status = idleOptimizePackages(pm, pkgs, lowStorageThreshold, isPostBootUpdate); logStatus(status); synchronized (mLock) { mLastExecutionStatus = status; mLastExecutionDurationMs = SystemClock.elapsedRealtime() - mLastExecutionStartTimeMs; mLastExecutionDurationIncludingSleepMs = SystemClock.elapsedRealtime() - mLastExecutionStartTimeMs; mLastExecutionDurationMs = SystemClock.uptimeMillis() - mLastExecutionStartUptimeMs; } return status == STATUS_OK || status == STATUS_DEX_OPT_FAILED; Loading Loading @@ -606,8 +612,8 @@ public final class BackgroundDexOptService { // Only downgrade apps when space is low on device. // Threshold is selected above the lowStorageThreshold so that we can pro-actively clean // up disk before user hits the actual lowStorageThreshold. long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE * lowStorageThreshold; long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE * lowStorageThreshold; boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade); if (DEBUG) { Slog.d(TAG, "Should Downgrade " + shouldDowngrade); Loading @@ -627,13 +633,14 @@ public final class BackgroundDexOptService { // Should be aborted by the scheduler. return abortCode; } @DexOptResult int downgradeResult = downgradePackage(snapshot, pm, pkg, @DexOptResult int downgradeResult = downgradePackage(snapshot, pm, pkg, /* isForPrimaryDex= */ true, isPostBootUpdate); if (downgradeResult == PackageDexOptimizer.DEX_OPT_PERFORMED) { updatedPackages.add(pkg); } @Status int status = convertPackageDexOptimizerStatusToInternal( downgradeResult); @Status int status = convertPackageDexOptimizerStatusToInternal(downgradeResult); if (status != STATUS_OK) { return status; } Loading Loading @@ -680,8 +687,8 @@ public final class BackgroundDexOptService { return abortCode; } @DexOptResult int primaryResult = optimizePackage(pkg, true /* isForPrimaryDex */, isPostBootUpdate); @DexOptResult int primaryResult = optimizePackage(pkg, true /* isForPrimaryDex */, isPostBootUpdate); if (primaryResult == PackageDexOptimizer.DEX_OPT_CANCELLED) { return STATUS_ABORT_BY_CANCELLATION; } Loading @@ -695,7 +702,8 @@ public final class BackgroundDexOptService { continue; } @DexOptResult int secondaryResult = @DexOptResult int secondaryResult = optimizePackage(pkg, false /* isForPrimaryDex */, isPostBootUpdate); if (secondaryResult == PackageDexOptimizer.DEX_OPT_CANCELLED) { return STATUS_ABORT_BY_CANCELLATION; Loading Loading @@ -794,22 +802,21 @@ public final class BackgroundDexOptService { } @DexOptResult private int performDexOptPrimary(String pkg, int reason, int dexoptFlags) { private int performDexOptPrimary(String pkg, int reason, int dexoptFlags) { DexoptOptions dexoptOptions = new DexoptOptions(pkg, reason, dexoptFlags); return trackPerformDexOpt(pkg, /*isForPrimaryDex=*/true, () -> mDexOptHelper.performDexOptWithStatus(dexoptOptions)); } @DexOptResult private int performDexOptSecondary(String pkg, int reason, int dexoptFlags) { DexoptOptions dexoptOptions = new DexoptOptions(pkg, reason, dexoptFlags | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX); private int performDexOptSecondary(String pkg, int reason, int dexoptFlags) { DexoptOptions dexoptOptions = new DexoptOptions( pkg, reason, dexoptFlags | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX); return trackPerformDexOpt(pkg, /*isForPrimaryDex=*/false, () -> mDexOptHelper.performDexOpt(dexoptOptions) ? PackageDexOptimizer.DEX_OPT_PERFORMED : PackageDexOptimizer.DEX_OPT_FAILED ); () -> mDexOptHelper.performDexOpt(dexoptOptions) ? PackageDexOptimizer.DEX_OPT_PERFORMED : PackageDexOptimizer.DEX_OPT_FAILED); } /** Loading @@ -822,8 +829,8 @@ public final class BackgroundDexOptService { * {@link PackageDexOptimizer#DEX_OPT_FAILED} */ @DexOptResult private int trackPerformDexOpt(String pkg, boolean isForPrimaryDex, Supplier<Integer> performDexOptWrapper) { private int trackPerformDexOpt( String pkg, boolean isForPrimaryDex, Supplier<Integer> performDexOptWrapper) { ArraySet<String> failedPackageNames; synchronized (mLock) { failedPackageNames = Loading Loading @@ -940,6 +947,19 @@ public final class BackgroundDexOptService { } } private void writeStatsLog(JobParameters params) { @Status int status; long durationMs; long durationIncludingSleepMs; synchronized (mLock) { status = mLastExecutionStatus; durationMs = mLastExecutionDurationMs; durationIncludingSleepMs = mLastExecutionDurationIncludingSleepMs; } mStatsLogger.write(status, params.getStopReason(), durationMs, durationIncludingSleepMs); } /** Injector pattern for testing purpose */ @VisibleForTesting static final class Injector { Loading Loading @@ -979,8 +999,8 @@ public final class BackgroundDexOptService { } boolean isBackgroundDexOptDisabled() { return SystemProperties.getBoolean("pm.dexopt.disable_bg_dexopt" /* key */, false /* default */); return SystemProperties.getBoolean( "pm.dexopt.disable_bg_dexopt" /* key */, false /* default */); } boolean isBatteryLevelLow() { Loading Loading @@ -1010,8 +1030,8 @@ public final class BackgroundDexOptService { } int getCurrentThermalStatus() { IThermalService thermalService = IThermalService.Stub .asInterface(ServiceManager.getService(Context.THERMAL_SERVICE)); IThermalService thermalService = IThermalService.Stub.asInterface( ServiceManager.getService(Context.THERMAL_SERVICE)); try { return thermalService.getCurrentThermalStatus(); } catch (RemoteException e) { Loading @@ -1020,8 +1040,8 @@ public final class BackgroundDexOptService { } int getDexOptThermalCutoff() { return SystemProperties.getInt("dalvik.vm.dexopt.thermal-cutoff", THERMAL_CUTOFF_DEFAULT); return SystemProperties.getInt( "dalvik.vm.dexopt.thermal-cutoff", THERMAL_CUTOFF_DEFAULT); } Thread createAndStartThread(String name, Runnable target) { Loading
services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java +29 −0 Original line number Diff line number Diff line Loading @@ -22,11 +22,13 @@ import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATI import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK; import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK; import android.app.job.JobParameters; import android.os.SystemClock; import android.util.Slog; import android.util.jar.StrictJarFile; import com.android.internal.art.ArtStatsLog; import com.android.server.pm.BackgroundDexOptService; import com.android.server.pm.PackageManagerService; import java.io.IOException; Loading Loading @@ -299,4 +301,31 @@ public class ArtStatsLogUtils { ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_UNKNOWN)); } } private static final Map<Integer, Integer> STATUS_MAP = Map.of(BackgroundDexOptService.STATUS_OK, ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_JOB_FINISHED, BackgroundDexOptService.STATUS_ABORT_BY_CANCELLATION, ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_BY_CANCELLATION, BackgroundDexOptService.STATUS_ABORT_NO_SPACE_LEFT, ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_NO_SPACE_LEFT, BackgroundDexOptService.STATUS_ABORT_THERMAL, ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_THERMAL, BackgroundDexOptService.STATUS_ABORT_BATTERY, ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_BATTERY, BackgroundDexOptService.STATUS_DEX_OPT_FAILED, ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_JOB_FINISHED); /** Helper class to write background dexopt job stats to statsd. */ public static class BackgroundDexoptJobStatsLogger { /** Writes background dexopt job stats to statsd. */ public void write(@BackgroundDexOptService.Status int status, @JobParameters.StopReason int cancellationReason, long durationMs, long durationIncludingSleepMs) { ArtStatsLog.write(ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED, STATUS_MAP.getOrDefault(status, ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_UNKNOWN), cancellationReason, durationMs, durationIncludingSleepMs); } } }