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
This commit is contained in:
Jiakai Zhang
2022-03-09 16:05:13 +00:00
parent 98a2f3a88b
commit 043872eb4c
3 changed files with 22 additions and 34 deletions

View File

@@ -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);

View File

@@ -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)) {

View File

@@ -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
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);
private void verifyPerformDexOpt(List<String> pkgs, int expectedRuns) {
InOrder inOrder = inOrder(mDexOptHelper);
for (int i = 0; i < expectedRuns; i++) {
for (String pkg : pkgs) {
inOrder.verify(mDexOptHelper, times(1)).performDexOptWithStatus(argThat((option) ->
option.getPackageName().equals(pkg) && !option.isDexoptOnlySecondaryDex()));
}
}
assertThat(primaryPkgs).isEmpty();
}
private static class StartAndWaitThread extends Thread {