From 043872eb4c5dbfd23ddcfbabf3860f783798d2d3 Mon Sep 17 00:00:00 2001 From: Jiakai Zhang Date: Wed, 9 Mar 2022 16:05:13 +0000 Subject: [PATCH] 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 --- .../server/pm/BackgroundDexOptService.java | 17 ++++----- .../com/android/server/pm/DexOptHelper.java | 4 +-- .../pm/BackgroundDexOptServiceUnitTest.java | 35 ++++++------------- 3 files changed, 22 insertions(+), 34 deletions(-) diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java index 9ff4aab83cffd..032b41f4bfcb1 100644 --- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java +++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java @@ -253,7 +253,8 @@ public final class BackgroundDexOptService { * *

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 packagesToOptimize; + List 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 pkgs = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer()); + List 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 pkgs, + private boolean runIdleOptimization(PackageManagerService pm, List pkgs, boolean isPostBootUpdate) { synchronized (mLock) { mLastExecutionStartTimeMs = SystemClock.elapsedRealtime(); @@ -581,7 +582,7 @@ public final class BackgroundDexOptService { } @Status - private int idleOptimizePackages(PackageManagerService pm, ArraySet pkgs, + private int idleOptimizePackages(PackageManagerService pm, List pkgs, long lowStorageThreshold, boolean isPostBootUpdate) { ArraySet updatedPackages = new ArraySet<>(); ArraySet 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 pkgs, long lowStorageThreshold, + private int optimizePackages(List pkgs, long lowStorageThreshold, boolean isForPrimaryDex, ArraySet updatedPackages, boolean isPostBootUpdate) { for (String pkg : pkgs) { int abortCode = abortIdleOptimizations(lowStorageThreshold); diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java index 50b2e23218864..bb2ba5cc498d1 100644 --- a/services/core/java/com/android/server/pm/DexOptHelper.java +++ b/services/core/java/com/android/server/pm/DexOptHelper.java @@ -293,8 +293,8 @@ final class DexOptHelper { MetricsLogger.histogram(mPm.mContext, "opt_dialog_time_s", elapsedTimeSeconds); } - public ArraySet getOptimizablePackages(@NonNull Computer snapshot) { - ArraySet pkgs = new ArraySet<>(); + public List getOptimizablePackages(@NonNull Computer snapshot) { + ArrayList pkgs = new ArrayList<>(); mPm.forEachPackageState(snapshot, packageState -> { final AndroidPackage pkg = packageState.getPkg(); if (pkg != null && mPm.mPackageDexOptimizer.canOptimizePackage(pkg)) { diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java index 6f503c7dd9418..b335749b7c174 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java @@ -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 DEFAULT_PACKAGE_LIST = new ArraySet<>( - Arrays.asList("aaa", "bbb")); - private static final ArraySet EMPTY_PACKAGE_LIST = new ArraySet<>(); + private static final List DEFAULT_PACKAGE_LIST = List.of("aaa", "bbb"); + private static final List 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 pkgs, int expectedRuns) { - ArgumentCaptor dexOptOptions = ArgumentCaptor.forClass(DexoptOptions.class); - verify(mDexOptHelper, atLeastOnce()).performDexOptWithStatus(dexOptOptions.capture()); - HashMap 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 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 {