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

Commit 043872eb authored by Jiakai Zhang's avatar Jiakai Zhang
Browse files

Use an ordered list for optimizable packages.

This allows us to order optimizable packages in the future.

Bug: 218666049
Test: atest FrameworksMockingServicesTests:BackgroundDexOptServiceUnitTest
Change-Id: Iee87cf41d269024132fd4c35a05e3bf40532c2a0
parent 98a2f3a8
Loading
Loading
Loading
Loading
+9 −8
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,7 +582,7 @@ 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<>();
@@ -640,7 +641,7 @@ public final class BackgroundDexOptService {
                        }
                    }

                    pkgs = new ArraySet<>(pkgs);
                    pkgs = new ArrayList<>(pkgs);
                    pkgs.removeAll(unusedPackages);
                }
            }
@@ -670,7 +671,7 @@ public final class BackgroundDexOptService {
    }

    @Status
    private int optimizePackages(ArraySet<String> pkgs, long lowStorageThreshold,
    private int optimizePackages(List<String> pkgs, long lowStorageThreshold,
            boolean isForPrimaryDex, ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
        for (String pkg : pkgs) {
            int abortCode = abortIdleOptimizations(lowStorageThreshold);
+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)) {
+11 −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;
@@ -418,26 +417,14 @@ 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()));
            }
        }
        assertThat(primaryPkgs).isEmpty();
    }

    private static class StartAndWaitThread extends Thread {