diff options
| -rw-r--r-- | services/core/java/com/android/server/pm/BackgroundDexOptService.java | 192 | ||||
| -rw-r--r-- | services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java | 29 |
2 files changed, 135 insertions, 86 deletions
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java index 9ea0192eaab5..5a01ccbb7d6f 100644 --- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java +++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java @@ -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; @@ -77,47 +78,46 @@ 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; - - @IntDef(prefix = {"STATUS_"}, value = { - STATUS_OK, - STATUS_ABORT_BY_CANCELLATION, - STATUS_ABORT_NO_SPACE_LEFT, - STATUS_ABORT_THERMAL, - STATUS_ABORT_BATTERY, - STATUS_DEX_OPT_FAILED, - }) + public static final int STATUS_DEX_OPT_FAILED = 5; + + @IntDef(prefix = {"STATUS_"}, + value = + { + STATUS_OK, + STATUS_ABORT_BY_CANCELLATION, + STATUS_ABORT_NO_SPACE_LEFT, + STATUS_ABORT_THERMAL, + STATUS_ABORT_BATTERY, + 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; @@ -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") @@ -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)); } @@ -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:"); @@ -361,17 +362,20 @@ 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() - + " completed:" + completed); + Slog.i(TAG, + "dexopt finishing. jobid:" + params.getJobId() + + " completed:" + completed); + + writeStatsLog(params); if (params.getJobId() == JOB_POST_BOOT_UPDATE) { if (completed) { @@ -455,7 +459,7 @@ public final class BackgroundDexOptService { if (mDexOptThread != Thread.currentThread()) { throw new IllegalStateException( "Only mDexOptThread can mark completion, mDexOptThread:" + mDexOptThread - + " current:" + Thread.currentThread()); + + " current:" + Thread.currentThread()); } mDexOptThread = null; // Other threads may be waiting for completion. @@ -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()); } @@ -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; @@ -555,7 +561,7 @@ public final class BackgroundDexOptService { private long getDirectorySize(File f) { long size = 0; if (f.isDirectory()) { - for (File file: f.listFiles()) { + for (File file : f.listFiles()) { size += getDirectorySize(file); } } else { @@ -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); @@ -627,19 +633,20 @@ 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; } if (supportSecondaryDex) { downgradeResult = downgradePackage(snapshot, pm, pkg, - /* isForPrimaryDex= */false, isPostBootUpdate); + /* isForPrimaryDex= */ false, isPostBootUpdate); status = convertPackageDexOptimizerStatusToInternal(downgradeResult); if (status != STATUS_OK) { return status; @@ -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; } @@ -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; @@ -748,7 +756,7 @@ public final class BackgroundDexOptService { if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) { final Computer newSnapshot = pm.snapshotComputer(); FrameworkStatsLog.write(FrameworkStatsLog.APP_DOWNGRADED, pkg, package_size_before, - getPackageSize(newSnapshot, pkg), /*aggressive=*/ false); + getPackageSize(newSnapshot, pkg), /*aggressive=*/false); } return result; } @@ -777,7 +785,7 @@ public final class BackgroundDexOptService { @DexOptResult private int optimizePackage(String pkg, boolean isForPrimaryDex, boolean isPostBootUpdate) { int reason = isPostBootUpdate ? PackageManagerService.REASON_POST_BOOT - : PackageManagerService.REASON_BACKGROUND_DEXOPT; + : PackageManagerService.REASON_BACKGROUND_DEXOPT; int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE; if (!isPostBootUpdate) { dexoptFlags |= DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES @@ -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, + 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); - return trackPerformDexOpt(pkg, /*isForPrimaryDex=*/ false, - () -> mDexOptHelper.performDexOpt(dexoptOptions) - ? PackageDexOptimizer.DEX_OPT_PERFORMED : PackageDexOptimizer.DEX_OPT_FAILED - ); + 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); } /** @@ -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 = @@ -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 { @@ -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() { @@ -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) { @@ -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) { diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java index b26b6940a1af..d49227dec454 100644 --- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java +++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java @@ -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; @@ -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); + } + } } |