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.
This commit is contained in:
Jiakai Zhang
2022-03-17 14:52:42 +00:00
committed by Android (Google) Code Review
3 changed files with 46 additions and 54 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,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;

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;
@@ -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
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()));
inOrder.verify(mDexOptHelper, times(1)).performDexOpt(argThat((option) ->
option.getPackageName().equals(pkg) && option.isDexoptOnlySecondaryDex()));
}
}
assertThat(primaryPkgs).isEmpty();
}
private static class StartAndWaitThread extends Thread {