Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aaa9af8a authored by Jiakai Zhang's avatar Jiakai Zhang Committed by Automerger Merge Worker
Browse files

Merge "Write stats when background dexopt job is ended." into tm-dev am: 303df2f8

parents 1a79ffbe 303df2f8
Loading
Loading
Loading
Loading
+106 −86
Original line number Diff line number Diff line
@@ -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,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,
@@ -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;
@@ -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,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);
@@ -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;
@@ -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,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;
                        }
@@ -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;
@@ -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);
    }

    /**
@@ -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) {
+29 −0
Original line number Diff line number Diff line
@@ -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);
        }
    }
}