Change the OptimizeResult API to allow multiple packages.
The API has to handle the case where FLAG_SHOULD_INCLUDE_DEPENDENCIES is
set, in which case more than one package are optimized. Also, the class
can be reused as the result class for batch optimization (optimizing
multiple packages).
Bug: 245301593
Test: atest ArtServiceTests
Ignore-AOSP-First: ART Services.
Change-Id: I5c634e536c9dbdbaedf2f161cbde62467fb27e91
diff --git a/libartservice/service/api/system-server-current.txt b/libartservice/service/api/system-server-current.txt
index ad988c2..c9ce7cd 100644
--- a/libartservice/service/api/system-server-current.txt
+++ b/libartservice/service/api/system-server-current.txt
@@ -67,10 +67,8 @@
}
public class OptimizeResult {
- ctor public OptimizeResult(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.List<com.android.server.art.model.OptimizeResult.DexFileOptimizeResult>);
- method @NonNull public java.util.List<com.android.server.art.model.OptimizeResult.DexFileOptimizeResult> getDexFileOptimizeResults();
method public int getFinalStatus();
- method @NonNull public String getPackageName();
+ method @NonNull public java.util.List<com.android.server.art.model.OptimizeResult.PackageOptimizeResult> getPackageOptimizeResults();
method @NonNull public String getReason();
method @NonNull public String getRequestedCompilerFilter();
field public static final int OPTIMIZE_CANCELLED = 40; // 0x28
@@ -86,5 +84,11 @@
method public int getStatus();
}
+ public static class OptimizeResult.PackageOptimizeResult {
+ method @NonNull public java.util.List<com.android.server.art.model.OptimizeResult.DexFileOptimizeResult> getDexFileOptimizeResults();
+ method @NonNull public String getPackageName();
+ method public int getStatus();
+ }
+
}
diff --git a/libartservice/service/java/com/android/server/art/ArtShellCommand.java b/libartservice/service/java/com/android/server/art/ArtShellCommand.java
index c207fc4..b797d8b 100644
--- a/libartservice/service/java/com/android/server/art/ArtShellCommand.java
+++ b/libartservice/service/java/com/android/server/art/ArtShellCommand.java
@@ -18,7 +18,11 @@
import static com.android.server.art.model.ArtFlags.OptimizeFlags;
import static com.android.server.art.model.OptimizationStatus.DexFileOptimizationStatus;
+import static com.android.server.art.model.OptimizeResult.DexFileOptimizeResult;
+import static com.android.server.art.model.OptimizeResult.OptimizeStatus;
+import static com.android.server.art.model.OptimizeResult.PackageOptimizeResult;
+import android.annotation.NonNull;
import android.os.Binder;
import android.os.Process;
@@ -93,19 +97,17 @@
}
OptimizeResult result = mArtManagerLocal.optimizePackage(
snapshot, getNextArgRequired(), paramsBuilder.build());
- switch (result.getFinalStatus()) {
- case OptimizeResult.OPTIMIZE_SKIPPED:
- pw.println("SKIPPED");
- break;
- case OptimizeResult.OPTIMIZE_PERFORMED:
- pw.println("PERFORMED");
- break;
- case OptimizeResult.OPTIMIZE_FAILED:
- pw.println("FAILED");
- break;
- case OptimizeResult.OPTIMIZE_CANCELLED:
- pw.println("CANCELLED");
- break;
+ pw.println(optimizeStatusToString(result.getFinalStatus()));
+ for (PackageOptimizeResult packageResult : result.getPackageOptimizeResults()) {
+ pw.printf("[%s]\n", packageResult.getPackageName());
+ for (DexFileOptimizeResult dexFileResult :
+ packageResult.getDexFileOptimizeResults()) {
+ pw.printf("dexFile = %s, instructionSet = %s, compilerFilter = %s, "
+ + "status = %s\n",
+ dexFileResult.getDexFile(), dexFileResult.getInstructionSet(),
+ dexFileResult.getActualCompilerFilter(),
+ optimizeStatusToString(dexFileResult.getStatus()));
+ }
}
return 0;
}
@@ -150,4 +152,19 @@
throw new SecurityException("ART service shell commands need root access");
}
}
+
+ @NonNull
+ private String optimizeStatusToString(@OptimizeStatus int status) {
+ switch (status) {
+ case OptimizeResult.OPTIMIZE_SKIPPED:
+ return "SKIPPED";
+ case OptimizeResult.OPTIMIZE_PERFORMED:
+ return "PERFORMED";
+ case OptimizeResult.OPTIMIZE_FAILED:
+ return "FAILED";
+ case OptimizeResult.OPTIMIZE_CANCELLED:
+ return "CANCELLED";
+ }
+ throw new IllegalArgumentException("Unknown optimize status " + status);
+ }
}
diff --git a/libartservice/service/java/com/android/server/art/DexOptHelper.java b/libartservice/service/java/com/android/server/art/DexOptHelper.java
index 6d9c85a..89bd8f4 100644
--- a/libartservice/service/java/com/android/server/art/DexOptHelper.java
+++ b/libartservice/service/java/com/android/server/art/DexOptHelper.java
@@ -17,6 +17,7 @@
package com.android.server.art;
import static com.android.server.art.model.OptimizeResult.DexFileOptimizeResult;
+import static com.android.server.art.model.OptimizeResult.PackageOptimizeResult;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -76,8 +77,8 @@
@NonNull OptimizeParams params) throws RemoteException {
List<DexFileOptimizeResult> results = new ArrayList<>();
Supplier<OptimizeResult> createResult = ()
- -> new OptimizeResult(pkgState.getPackageName(), params.getCompilerFilter(),
- params.getReason(), results);
+ -> new OptimizeResult(params.getCompilerFilter(), params.getReason(),
+ List.of(new PackageOptimizeResult(pkgState.getPackageName(), results)));
if (!canOptimizePackage(pkgState, pkg)) {
return createResult.get();
diff --git a/libartservice/service/java/com/android/server/art/model/OptimizeResult.java b/libartservice/service/java/com/android/server/art/model/OptimizeResult.java
index d6fdf28..f1c83d4 100644
--- a/libartservice/service/java/com/android/server/art/model/OptimizeResult.java
+++ b/libartservice/service/java/com/android/server/art/model/OptimizeResult.java
@@ -50,22 +50,16 @@
@Retention(RetentionPolicy.SOURCE)
public @interface OptimizeStatus {}
- private final @NonNull String mPackageName;
private final @NonNull String mRequestedCompilerFilter;
private final @NonNull String mReason;
- private final @NonNull List<DexFileOptimizeResult> mDexFileOptimizeResults;
+ private final @NonNull List<PackageOptimizeResult> mPackageOptimizeResult;
- public OptimizeResult(@NonNull String packageName, @NonNull String requestedCompilerFilter,
- @NonNull String reason, @NonNull List<DexFileOptimizeResult> dexFileOptimizeResults) {
- mPackageName = packageName;
+ /** @hide */
+ public OptimizeResult(@NonNull String requestedCompilerFilter, @NonNull String reason,
+ @NonNull List<PackageOptimizeResult> packageOptimizeResult) {
mRequestedCompilerFilter = requestedCompilerFilter;
mReason = reason;
- mDexFileOptimizeResults = dexFileOptimizeResults;
- }
-
- /** The package name. */
- public @NonNull String getPackageName() {
- return mPackageName;
+ mPackageOptimizeResult = packageOptimizeResult;
}
/**
@@ -84,18 +78,63 @@
return mReason;
}
+ /**
+ * The result of each individual package.
+ *
+ * If the request is to optimize a single package without optimizing dependencies, the only
+ * element is the result of the requested package.
+ *
+ * If the request is to optimize a single package with {@link
+ * ArtFlags.FLAG_SHOULD_INCLUDE_DEPENDENCIES} set, the first element is the result of the
+ * requested package, and the rest are the results of the dependency packages.
+ *
+ * If the request is to optimize multiple packages, the list contains the results of all the
+ * requested packages. The results of their dependency packages are also included if {@link
+ * ArtFlags.FLAG_SHOULD_INCLUDE_DEPENDENCIES} is set.
+ */
+ public @NonNull List<PackageOptimizeResult> getPackageOptimizeResults() {
+ return mPackageOptimizeResult;
+ }
+
/** The final status. */
public @OptimizeStatus int getFinalStatus() {
- return mDexFileOptimizeResults.stream()
+ return mPackageOptimizeResult.stream()
.mapToInt(result -> result.getStatus())
.max()
.orElse(OPTIMIZE_SKIPPED);
}
- /** The result of each individual dex file. */
- @NonNull
- public List<DexFileOptimizeResult> getDexFileOptimizeResults() {
- return mDexFileOptimizeResults;
+ /** Describes the result of a package. */
+ @Immutable
+ public static class PackageOptimizeResult {
+ private final @NonNull String mPackageName;
+ private final @NonNull List<DexFileOptimizeResult> mDexFileOptimizeResults;
+
+ /** @hide */
+ public PackageOptimizeResult(@NonNull String packageName,
+ @NonNull List<DexFileOptimizeResult> dexFileOptimizeResults) {
+ mPackageName = packageName;
+ mDexFileOptimizeResults = dexFileOptimizeResults;
+ }
+
+ /** The package name. */
+ public @NonNull String getPackageName() {
+ return mPackageName;
+ }
+
+ /** The result of each individual dex file. */
+ @NonNull
+ public List<DexFileOptimizeResult> getDexFileOptimizeResults() {
+ return mDexFileOptimizeResults;
+ }
+
+ /** The overall status of the package. */
+ public @OptimizeStatus int getStatus() {
+ return mDexFileOptimizeResults.stream()
+ .mapToInt(result -> result.getStatus())
+ .max()
+ .orElse(OPTIMIZE_SKIPPED);
+ }
}
/** Describes the result of a dex file. */
diff --git a/libartservice/service/javatests/com/android/server/art/DexOptHelperTest.java b/libartservice/service/javatests/com/android/server/art/DexOptHelperTest.java
index 518b972..3b4e045 100644
--- a/libartservice/service/javatests/com/android/server/art/DexOptHelperTest.java
+++ b/libartservice/service/javatests/com/android/server/art/DexOptHelperTest.java
@@ -17,6 +17,7 @@
package com.android.server.art;
import static com.android.server.art.model.OptimizeResult.DexFileOptimizeResult;
+import static com.android.server.art.model.OptimizeResult.PackageOptimizeResult;
import static com.google.common.truth.Truth.assertThat;
@@ -109,11 +110,15 @@
OptimizeResult result =
mDexOptHelper.dexopt(mock(PackageDataSnapshot.class), mPkgState, mPkg, mParams);
- assertThat(result.getPackageName()).isEqualTo(PKG_NAME);
assertThat(result.getRequestedCompilerFilter()).isEqualTo("speed-profile");
assertThat(result.getReason()).isEqualTo("install");
assertThat(result.getFinalStatus()).isEqualTo(OptimizeResult.OPTIMIZE_FAILED);
- assertThat(result.getDexFileOptimizeResults()).containsExactlyElementsIn(mPrimaryResults);
+ assertThat(result.getPackageOptimizeResults()).hasSize(1);
+
+ PackageOptimizeResult packageResult = result.getPackageOptimizeResults().get(0);
+ assertThat(packageResult.getPackageName()).isEqualTo(PKG_NAME);
+ assertThat(packageResult.getDexFileOptimizeResults())
+ .containsExactlyElementsIn(mPrimaryResults);
InOrder inOrder = inOrder(mPrimaryDexOptimizer, mWakeLock);
inOrder.verify(mWakeLock).acquire(anyLong());
@@ -129,7 +134,7 @@
mDexOptHelper.dexopt(mock(PackageDataSnapshot.class), mPkgState, mPkg, mParams);
assertThat(result.getFinalStatus()).isEqualTo(OptimizeResult.OPTIMIZE_SKIPPED);
- assertThat(result.getDexFileOptimizeResults()).isEmpty();
+ assertThat(result.getPackageOptimizeResults().get(0).getDexFileOptimizeResults()).isEmpty();
}
@Test
@@ -140,7 +145,7 @@
mDexOptHelper.dexopt(mock(PackageDataSnapshot.class), mPkgState, mPkg, mParams);
assertThat(result.getFinalStatus()).isEqualTo(OptimizeResult.OPTIMIZE_SKIPPED);
- assertThat(result.getDexFileOptimizeResults()).isEmpty();
+ assertThat(result.getPackageOptimizeResults().get(0).getDexFileOptimizeResults()).isEmpty();
}
@Test
@@ -154,7 +159,8 @@
OptimizeResult result =
mDexOptHelper.dexopt(mock(PackageDataSnapshot.class), mPkgState, mPkg, mParams);
- assertThat(result.getDexFileOptimizeResults()).containsExactlyElementsIn(mPrimaryResults);
+ assertThat(result.getPackageOptimizeResults().get(0).getDexFileOptimizeResults())
+ .containsExactlyElementsIn(mPrimaryResults);
}
@Test