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

Commit a8e95182 authored by Jiakai Zhang's avatar Jiakai Zhang Committed by Android (Google) Code Review
Browse files

Merge changes from topics "presubmit-am-ccc6c143101b468f83145a298c1082f9",...

Merge changes from topics "presubmit-am-ccc6c143101b468f83145a298c1082f9", "presubmit-am-d0ebefcda3024c72ada77080939a22c1" into tm-dev

* changes:
  Optimize primary and secondary dex’es together.
  Use an ordered list for optimizable packages.
parents 9fb2dca0 ac4ca45f
Loading
Loading
Loading
Loading
+29 −28
Original line number Diff line number Diff line
@@ -253,7 +253,8 @@ public final class BackgroundDexOptService {
     *
     * <p>This is only for shell command and only root or shell user can use this.
     *
     * @param packageNames dex optimize the passed packages or all packages if null
     * @param packageNames dex optimize the passed packages in the given order, or all packages in
     *         the default order if null
     *
     * @return true if dex optimization is complete. false if the task is cancelled or if there was
     *         an error.
@@ -268,11 +269,11 @@ public final class BackgroundDexOptService {
                resetStatesForNewDexOptRunLocked(Thread.currentThread());
            }
            PackageManagerService pm = mInjector.getPackageManagerService();
            ArraySet<String> packagesToOptimize;
            List<String> packagesToOptimize;
            if (packageNames == null) {
                packagesToOptimize = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
            } else {
                packagesToOptimize = new ArraySet<>(packageNames);
                packagesToOptimize = packageNames;
            }
            return runIdleOptimization(pm, packagesToOptimize, /* isPostBootUpdate= */ false);
        } finally {
@@ -335,7 +336,7 @@ public final class BackgroundDexOptService {
            return false;
        }

        ArraySet<String> pkgs = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
        List<String> pkgs = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
        if (pkgs.isEmpty()) {
            Slog.i(TAG, "No packages to optimize");
            markPostBootUpdateCompleted(params);
@@ -525,7 +526,7 @@ public final class BackgroundDexOptService {
    }

    /** Returns true if completed */
    private boolean runIdleOptimization(PackageManagerService pm, ArraySet<String> pkgs,
    private boolean runIdleOptimization(PackageManagerService pm, List<String> pkgs,
            boolean isPostBootUpdate) {
        synchronized (mLock) {
            mLastExecutionStartTimeMs = SystemClock.elapsedRealtime();
@@ -581,10 +582,9 @@ public final class BackgroundDexOptService {
    }

    @Status
    private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
    private int idleOptimizePackages(PackageManagerService pm, List<String> pkgs,
            long lowStorageThreshold, boolean isPostBootUpdate) {
        ArraySet<String> updatedPackages = new ArraySet<>();
        ArraySet<String> updatedPackagesDueToSecondaryDex = new ArraySet<>();

        try {
            boolean supportSecondaryDex = mInjector.supportSecondaryDex();
@@ -640,25 +640,12 @@ public final class BackgroundDexOptService {
                        }
                    }

                    pkgs = new ArraySet<>(pkgs);
                    pkgs = new ArrayList<>(pkgs);
                    pkgs.removeAll(unusedPackages);
                }
            }

            @Status int primaryResult = optimizePackages(pkgs, lowStorageThreshold,
                    /*isForPrimaryDex=*/ true, updatedPackages, isPostBootUpdate);
            if (primaryResult != STATUS_OK) {
                return primaryResult;
            }

            if (!supportSecondaryDex) {
                return STATUS_OK;
            }

            @Status int secondaryResult = optimizePackages(pkgs, lowStorageThreshold,
                    /*isForPrimaryDex*/ false, updatedPackagesDueToSecondaryDex,
                    isPostBootUpdate);
            return secondaryResult;
            return optimizePackages(pkgs, lowStorageThreshold, updatedPackages, isPostBootUpdate);
        } finally {
            // Always let the pinner service know about changes.
            notifyPinService(updatedPackages);
@@ -670,8 +657,10 @@ public final class BackgroundDexOptService {
    }

    @Status
    private int optimizePackages(ArraySet<String> pkgs, long lowStorageThreshold,
            boolean isForPrimaryDex, ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
    private int optimizePackages(List<String> pkgs, long lowStorageThreshold,
            ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
        boolean supportSecondaryDex = mInjector.supportSecondaryDex();

        for (String pkg : pkgs) {
            int abortCode = abortIdleOptimizations(lowStorageThreshold);
            if (abortCode != STATUS_OK) {
@@ -679,11 +668,23 @@ public final class BackgroundDexOptService {
                return abortCode;
            }

            @DexOptResult int result = optimizePackage(pkg, isForPrimaryDex, isPostBootUpdate);
            if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
            @DexOptResult int primaryResult =
                    optimizePackage(pkg, true /* isForPrimaryDex */, isPostBootUpdate);
            if (primaryResult == PackageDexOptimizer.DEX_OPT_PERFORMED) {
                updatedPackages.add(pkg);
            } else if (result != PackageDexOptimizer.DEX_OPT_SKIPPED) {
                return convertPackageDexOptimizerStatusToInternal(result);
            } else if (primaryResult != PackageDexOptimizer.DEX_OPT_SKIPPED) {
                return convertPackageDexOptimizerStatusToInternal(primaryResult);
            }

            if (!supportSecondaryDex) {
                continue;
            }

            @DexOptResult int secondaryResult =
                    optimizePackage(pkg, false /* isForPrimaryDex */, isPostBootUpdate);
            if (secondaryResult != PackageDexOptimizer.DEX_OPT_PERFORMED
                    && secondaryResult != PackageDexOptimizer.DEX_OPT_SKIPPED) {
                return convertPackageDexOptimizerStatusToInternal(secondaryResult);
            }
        }
        return STATUS_OK;
+2 −2
Original line number Diff line number Diff line
@@ -293,8 +293,8 @@ final class DexOptHelper {
        MetricsLogger.histogram(mPm.mContext, "opt_dialog_time_s", elapsedTimeSeconds);
    }

    public ArraySet<String> getOptimizablePackages(@NonNull Computer snapshot) {
        ArraySet<String> pkgs = new ArraySet<>();
    public List<String> getOptimizablePackages(@NonNull Computer snapshot) {
        ArrayList<String> pkgs = new ArrayList<>();
        mPm.forEachPackageState(snapshot, packageState -> {
            final AndroidPackage pkg = packageState.getPkg();
            if (pkg != null && mPm.mPackageDexOptimizer.canOptimizePackage(pkg)) {
+15 −24
Original line number Diff line number Diff line
@@ -19,7 +19,9 @@ package com.android.server.pm;
import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
@@ -36,23 +38,21 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.os.HandlerThread;
import android.os.PowerManager;
import android.util.ArraySet;

import com.android.server.LocalServices;
import com.android.server.PinnerService;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
@@ -66,9 +66,8 @@ public final class BackgroundDexOptServiceUnitTest {

    private static final long TEST_WAIT_TIMEOUT_MS = 10_000;

    private static final ArraySet<String> DEFAULT_PACKAGE_LIST = new ArraySet<>(
            Arrays.asList("aaa", "bbb"));
    private static final ArraySet<String> EMPTY_PACKAGE_LIST = new ArraySet<>();
    private static final List<String> DEFAULT_PACKAGE_LIST = List.of("aaa", "bbb");
    private static final List<String> EMPTY_PACKAGE_LIST = List.of();

    @Mock
    private Context mContext;
@@ -116,9 +115,11 @@ public final class BackgroundDexOptServiceUnitTest {
        when(mInjector.getDataDirStorageLowBytes()).thenReturn(STORAGE_LOW_BYTES);
        when(mInjector.getDexOptThermalCutoff()).thenReturn(PowerManager.THERMAL_STATUS_CRITICAL);
        when(mInjector.getCurrentThermalStatus()).thenReturn(PowerManager.THERMAL_STATUS_NONE);
        when(mInjector.supportSecondaryDex()).thenReturn(true);
        when(mDexOptHelper.getOptimizablePackages(any())).thenReturn(DEFAULT_PACKAGE_LIST);
        when(mDexOptHelper.performDexOptWithStatus(any())).thenReturn(
                PackageDexOptimizer.DEX_OPT_PERFORMED);
        when(mDexOptHelper.performDexOpt(any())).thenReturn(true);

        mService = new BackgroundDexOptService(mInjector);
    }
@@ -418,26 +419,16 @@ public final class BackgroundDexOptServiceUnitTest {
        verifyPerformDexOpt(DEFAULT_PACKAGE_LIST, totalJobRuns);
    }

    private void verifyPerformDexOpt(ArraySet<String> pkgs, int expectedRuns) {
        ArgumentCaptor<DexoptOptions> dexOptOptions = ArgumentCaptor.forClass(DexoptOptions.class);
        verify(mDexOptHelper, atLeastOnce()).performDexOptWithStatus(dexOptOptions.capture());
        HashMap<String, Integer> primaryPkgs = new HashMap<>(); // K: pkg, V: dexopt runs left
    private void verifyPerformDexOpt(List<String> pkgs, int expectedRuns) {
        InOrder inOrder = inOrder(mDexOptHelper);
        for (int i = 0; i < expectedRuns; i++) {
            for (String pkg : pkgs) {
            primaryPkgs.put(pkg, expectedRuns);
        }

        for (DexoptOptions opt : dexOptOptions.getAllValues()) {
            assertThat(pkgs).contains(opt.getPackageName());
            assertThat(opt.isDexoptOnlySecondaryDex()).isFalse();
            Integer count = primaryPkgs.get(opt.getPackageName());
            assertThat(count).isNotNull();
            if (count == 1) {
                primaryPkgs.remove(opt.getPackageName());
            } else {
                primaryPkgs.put(opt.getPackageName(), count - 1);
                inOrder.verify(mDexOptHelper, times(1)).performDexOptWithStatus(argThat((option) ->
                        option.getPackageName().equals(pkg) && !option.isDexoptOnlySecondaryDex()));
                inOrder.verify(mDexOptHelper, times(1)).performDexOpt(argThat((option) ->
                        option.getPackageName().equals(pkg) && option.isDexoptOnlySecondaryDex()));
            }
        }
        assertThat(primaryPkgs).isEmpty();
    }

    private static class StartAndWaitThread extends Thread {