diff options
6 files changed, 168 insertions, 60 deletions
diff --git a/libartservice/service/java/com/android/server/art/ArtManagedInstallFileHelper.java b/libartservice/service/java/com/android/server/art/ArtManagedInstallFileHelper.java index dd040165e3..53d88c2588 100644 --- a/libartservice/service/java/com/android/server/art/ArtManagedInstallFileHelper.java +++ b/libartservice/service/java/com/android/server/art/ArtManagedInstallFileHelper.java @@ -25,9 +25,12 @@ import androidx.annotation.RequiresApi; import com.android.art.flags.Flags; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Helper class for <i>ART-managed install files</i> (files installed by Package Manager @@ -41,6 +44,11 @@ import java.util.stream.Collectors; public final class ArtManagedInstallFileHelper { private static final List<String> FILE_TYPES = List.of(ArtConstants.DEX_METADATA_FILE_EXT, ArtConstants.PROFILE_FILE_EXT, ArtConstants.SECURE_DEX_METADATA_FILE_EXT); + private static final List<String> SDM_SUFFIXES = + Utils.getNativeIsas() + .stream() + .map(isa -> "." + isa + ArtConstants.SECURE_DEX_METADATA_FILE_EXT) + .toList(); private ArtManagedInstallFileHelper() {} @@ -64,9 +72,14 @@ public final class ArtManagedInstallFileHelper { @FlaggedApi(Flags.FLAG_ART_SERVICE_V3) public static @NonNull List<String> filterPathsForApk( @NonNull List<String> paths, @NonNull String apkPath) { - Set<String> candidates = FILE_TYPES.stream() - .map(ext -> Utils.replaceFileExtension(apkPath, ext)) - .collect(Collectors.toSet()); + Set<String> candidates = + FILE_TYPES.stream() + .flatMap(ext + -> ext.equals(ArtConstants.SECURE_DEX_METADATA_FILE_EXT) + ? SDM_SUFFIXES.stream().map(suffix + -> Utils.replaceFileExtension(apkPath, suffix)) + : Stream.of(Utils.replaceFileExtension(apkPath, ext))) + .collect(Collectors.toSet()); return paths.stream().filter(path -> candidates.contains(path)).toList(); } @@ -84,10 +97,23 @@ public final class ArtManagedInstallFileHelper { public static @NonNull String getTargetPathForApk( @NonNull String originalPath, @NonNull String apkPath) { for (String ext : FILE_TYPES) { - if (originalPath.endsWith(ext)) { + if (!ext.equals(ArtConstants.SECURE_DEX_METADATA_FILE_EXT) + && originalPath.endsWith(ext)) { return Utils.replaceFileExtension(apkPath, ext); } } + if (originalPath.endsWith(ArtConstants.SECURE_DEX_METADATA_FILE_EXT)) { + for (String suffix : SDM_SUFFIXES) { + if (originalPath.endsWith(suffix)) { + return Utils.replaceFileExtension(apkPath, suffix); + } + } + AsLog.w("SDM filename '" + originalPath + + "' does not contain a valid instruction set name"); + Path dirname = Paths.get(apkPath).getParent(); + Path basename = Paths.get(originalPath).getFileName(); + return (dirname != null ? dirname.resolve(basename) : basename).toString(); + } throw new IllegalArgumentException( "Illegal ART managed install file path '" + originalPath + "'"); } diff --git a/libartservice/service/java/com/android/server/art/ArtManagerLocal.java b/libartservice/service/java/com/android/server/art/ArtManagerLocal.java index e202c4fecc..d8a508eb4e 100644 --- a/libartservice/service/java/com/android/server/art/ArtManagerLocal.java +++ b/libartservice/service/java/com/android/server/art/ArtManagerLocal.java @@ -1014,7 +1014,7 @@ public final class ArtManagerLocal { public void dump(@NonNull PrintWriter pw, @NonNull PackageManagerLocal.FilteredSnapshot snapshot, boolean verifySdmSignatures) { try (var pin = mInjector.createArtdPin()) { - new DumpHelper(this).dump(pw, snapshot, verifySdmSignatures); + new DumpHelper(this, verifySdmSignatures).dump(pw, snapshot); } } @@ -1043,8 +1043,8 @@ public final class ArtManagerLocal { @NonNull PackageManagerLocal.FilteredSnapshot snapshot, @NonNull String packageName, boolean verifySdmSignatures) { try (var pin = mInjector.createArtdPin()) { - new DumpHelper(this).dumpPackage(pw, snapshot, - Utils.getPackageStateOrThrow(snapshot, packageName), verifySdmSignatures); + new DumpHelper(this, verifySdmSignatures) + .dumpPackage(pw, snapshot, Utils.getPackageStateOrThrow(snapshot, packageName)); } } diff --git a/libartservice/service/java/com/android/server/art/DumpHelper.java b/libartservice/service/java/com/android/server/art/DumpHelper.java index 9578652120..77cc37f4b3 100644 --- a/libartservice/service/java/com/android/server/art/DumpHelper.java +++ b/libartservice/service/java/com/android/server/art/DumpHelper.java @@ -60,24 +60,26 @@ import java.util.stream.Collectors; @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public class DumpHelper { @NonNull private final Injector mInjector; + private final boolean mVerifySdmSignatures; - public DumpHelper(@NonNull ArtManagerLocal artManagerLocal) { - this(new Injector(artManagerLocal)); + public DumpHelper(@NonNull ArtManagerLocal artManagerLocal, boolean verifySdmSignatures) { + this(new Injector(artManagerLocal), verifySdmSignatures); } @VisibleForTesting - public DumpHelper(@NonNull Injector injector) { + public DumpHelper(@NonNull Injector injector, boolean verifySdmSignatures) { mInjector = injector; + mVerifySdmSignatures = verifySdmSignatures; } /** Handles {@link ArtManagerLocal#dump(PrintWriter, PackageManagerLocal.FilteredSnapshot)}. */ - public void dump(@NonNull PrintWriter pw, - @NonNull PackageManagerLocal.FilteredSnapshot snapshot, boolean verifySdmSignatures) { + public void dump( + @NonNull PrintWriter pw, @NonNull PackageManagerLocal.FilteredSnapshot snapshot) { snapshot.getPackageStates() .values() .stream() .sorted(Comparator.comparing(PackageState::getPackageName)) - .forEach(pkgState -> dumpPackage(pw, snapshot, pkgState, verifySdmSignatures)); + .forEach(pkgState -> dumpPackage(pw, snapshot, pkgState)); pw.printf("\nCurrent GC: %s\n", ArtJni.getGarbageCollector()); } @@ -86,8 +88,8 @@ public class DumpHelper { * ArtManagerLocal#dumpPackage(PrintWriter, PackageManagerLocal.FilteredSnapshot, String)}. */ public void dumpPackage(@NonNull PrintWriter pw, - @NonNull PackageManagerLocal.FilteredSnapshot snapshot, @NonNull PackageState pkgState, - boolean verifySdmSignatures) { + @NonNull PackageManagerLocal.FilteredSnapshot snapshot, + @NonNull PackageState pkgState) { if (pkgState.isApex() || pkgState.getAndroidPackage() == null) { return; } @@ -130,7 +132,7 @@ public class DumpHelper { ipw.increaseIndent(); for (List<DexContainerFileDexoptStatus> fileStatuses : primaryStatusesByDexPath.values()) { - dumpPrimaryDex(ipw, snapshot, fileStatuses, packageName, verifySdmSignatures); + dumpPrimaryDex(ipw, snapshot, fileStatuses, packageName); } if (!secondaryStatusesByDexPath.isEmpty()) { ipw.println("known secondary dex files:"); @@ -147,8 +149,7 @@ public class DumpHelper { private void dumpPrimaryDex(@NonNull IndentingPrintWriter ipw, @NonNull PackageManagerLocal.FilteredSnapshot snapshot, - List<DexContainerFileDexoptStatus> fileStatuses, @NonNull String packageName, - boolean verifySdmSignatures) { + List<DexContainerFileDexoptStatus> fileStatuses, @NonNull String packageName) { String dexPath = fileStatuses.get(0).getDexContainerFile(); ipw.printf("path: %s\n", dexPath); ipw.increaseIndent(); @@ -156,7 +157,6 @@ public class DumpHelper { dumpUsedByOtherApps(ipw, snapshot, mInjector.getDexUseManager().getPrimaryDexLoaders(packageName, dexPath), packageName); - dumpSdmStatus(ipw, dexPath, verifySdmSignatures); ipw.decreaseIndent(); } @@ -199,12 +199,15 @@ public class DumpHelper { private void dumpFileStatuses( @NonNull IndentingPrintWriter ipw, List<DexContainerFileDexoptStatus> fileStatuses) { for (DexContainerFileDexoptStatus fileStatus : fileStatuses) { - ipw.printf("%s: [status=%s] [reason=%s]%s\n", - VMRuntime.getInstructionSet(fileStatus.getAbi()), - fileStatus.getCompilerFilter(), fileStatus.getCompilationReason(), + String isa = VMRuntime.getInstructionSet(fileStatus.getAbi()); + ipw.printf("%s: [status=%s] [reason=%s]%s\n", isa, fileStatus.getCompilerFilter(), + fileStatus.getCompilationReason(), fileStatus.isPrimaryAbi() ? " [primary-abi]" : ""); ipw.increaseIndent(); ipw.printf("[location is %s]\n", fileStatus.getLocationDebugString()); + if (fileStatus.isPrimaryDex()) { + dumpSdmStatus(ipw, fileStatus.getDexContainerFile(), isa); + } ipw.decreaseIndent(); } } @@ -225,13 +228,13 @@ public class DumpHelper { } } - private void dumpSdmStatus(@NonNull IndentingPrintWriter ipw, @NonNull String dexPath, - boolean verifySdmSignatures) { + private void dumpSdmStatus( + @NonNull IndentingPrintWriter ipw, @NonNull String dexPath, @NonNull String isa) { if (!android.content.pm.Flags.cloudCompilationPm()) { return; } - String sdmPath = getSdmPath(dexPath); + String sdmPath = getSdmPath(dexPath, isa); String status = ""; String signature = "skipped"; if (mInjector.fileExists(sdmPath)) { @@ -239,7 +242,7 @@ public class DumpHelper { // because SDM files are not supported yet. status = "pending"; // This operation is expensive, so hide it behind a flag. - if (verifySdmSignatures) { + if (mVerifySdmSignatures) { signature = getSdmSignatureStatus(dexPath, sdmPath); } } @@ -283,8 +286,9 @@ public class DumpHelper { } @NonNull - private static String getSdmPath(@NonNull String dexPath) { - return Utils.replaceFileExtension(dexPath, ArtConstants.SECURE_DEX_METADATA_FILE_EXT); + private static String getSdmPath(@NonNull String dexPath, @NonNull String isa) { + return Utils.replaceFileExtension( + dexPath, "." + isa + ArtConstants.SECURE_DEX_METADATA_FILE_EXT); } @NonNull diff --git a/libartservice/service/java/com/android/server/art/Utils.java b/libartservice/service/java/com/android/server/art/Utils.java index 07168aa07e..3dcbc54141 100644 --- a/libartservice/service/java/com/android/server/art/Utils.java +++ b/libartservice/service/java/com/android/server/art/Utils.java @@ -67,6 +67,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -204,6 +205,14 @@ public final class Utils { || abiName.equals(Constants.getNative32BitAbi()); } + public static List<String> getNativeIsas() { + return Arrays.asList(Constants.getNative64BitAbi(), Constants.getNative32BitAbi()) + .stream() + .filter(Objects::nonNull) + .map(VMRuntime::getInstructionSet) + .toList(); + } + /** * Returns whether the artifacts of the primary dex files should be in the global dalvik-cache * directory. diff --git a/libartservice/service/javatests/com/android/server/art/ArtManagedInstallFileHelperTest.java b/libartservice/service/javatests/com/android/server/art/ArtManagedInstallFileHelperTest.java index 4b13716eaa..b0b52fae9e 100644 --- a/libartservice/service/javatests/com/android/server/art/ArtManagedInstallFileHelperTest.java +++ b/libartservice/service/javatests/com/android/server/art/ArtManagedInstallFileHelperTest.java @@ -19,10 +19,15 @@ package com.android.server.art; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.lenient; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.server.art.testing.StaticMockitoRule; + +import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -31,33 +36,45 @@ import java.util.List; @SmallTest @RunWith(AndroidJUnit4.class) public class ArtManagedInstallFileHelperTest { + @Rule public StaticMockitoRule mockitoRule = new StaticMockitoRule(Constants.class); + + @Before + public void setUp() throws Exception { + lenient().when(Constants.getNative64BitAbi()).thenReturn("arm64-v8a"); + lenient().when(Constants.getNative32BitAbi()).thenReturn("armeabi-v7a"); + } + @Test public void testIsArtManaged() throws Exception { assertThat(ArtManagedInstallFileHelper.isArtManaged("/foo/bar.dm")).isTrue(); assertThat(ArtManagedInstallFileHelper.isArtManaged("/foo/bar.prof")).isTrue(); assertThat(ArtManagedInstallFileHelper.isArtManaged("/foo/bar.sdm")).isTrue(); + assertThat(ArtManagedInstallFileHelper.isArtManaged("/foo/bar.arm.sdm")).isTrue(); + assertThat(ArtManagedInstallFileHelper.isArtManaged("/foo/bar.arm64.sdm")).isTrue(); assertThat(ArtManagedInstallFileHelper.isArtManaged("/foo/bar.abc")).isFalse(); } @Test public void testFilterPathsForApk() throws Exception { assertThat(ArtManagedInstallFileHelper.filterPathsForApk( - List.of("/foo/bar.dm", "/foo/bar.prof", "/foo/bar.sdm", "/foo/bar.abc", - "/foo/baz.dm"), + List.of("/foo/bar.dm", "/foo/bar.prof", "/foo/bar.sdm", + "/foo/bar.x86_64.sdm", "/foo/bar.arm.sdm", "/foo/bar.arm64.sdm", + "/foo/bar.abc", "/foo/baz.dm"), "/foo/bar.apk")) - .containsExactly("/foo/bar.dm", "/foo/bar.prof", "/foo/bar.sdm"); + .containsExactly( + "/foo/bar.dm", "/foo/bar.prof", "/foo/bar.arm.sdm", "/foo/bar.arm64.sdm"); // Filenames don't match. assertThat(ArtManagedInstallFileHelper.filterPathsForApk( - List.of("/foo/bar.dm", "/foo/bar.prof", "/foo/bar.sdm", "/foo/bar.abc", - "/foo/baz.dm"), + List.of("/foo/bar.dm", "/foo/bar.prof", "/foo/bar.arm64.sdm", + "/foo/bar.abc", "/foo/baz.dm"), "/foo/qux.apk")) .isEmpty(); // Directories don't match. assertThat(ArtManagedInstallFileHelper.filterPathsForApk( - List.of("/foo/bar.dm", "/foo/bar.prof", "/foo/bar.sdm", "/foo/bar.abc", - "/foo/baz.dm"), + List.of("/foo/bar.dm", "/foo/bar.prof", "/foo/bar.arm64.sdm", + "/foo/bar.abc", "/foo/baz.dm"), "/quz/bar.apk")) .isEmpty(); } @@ -71,8 +88,22 @@ public class ArtManagedInstallFileHelperTest { "/foo/bar.prof", "/somewhere/base.apk")) .isEqualTo("/somewhere/base.prof"); assertThat(ArtManagedInstallFileHelper.getTargetPathForApk( + "/foo/bar.arm.sdm", "/somewhere/base.apk")) + .isEqualTo("/somewhere/base.arm.sdm"); + assertThat(ArtManagedInstallFileHelper.getTargetPathForApk( + "/foo/bar.arm64.sdm", "/somewhere/base.apk")) + .isEqualTo("/somewhere/base.arm64.sdm"); + + // None or invalid ISA. + assertThat(ArtManagedInstallFileHelper.getTargetPathForApk( "/foo/bar.sdm", "/somewhere/base.apk")) - .isEqualTo("/somewhere/base.sdm"); + .isEqualTo("/somewhere/bar.sdm"); + assertThat(ArtManagedInstallFileHelper.getTargetPathForApk( + "/foo/bar.x86_64.sdm", "/somewhere/base.apk")) + .isEqualTo("/somewhere/bar.x86_64.sdm"); + assertThat(ArtManagedInstallFileHelper.getTargetPathForApk( + "/foo/bar.invalid-isa.sdm", "/somewhere/base.apk")) + .isEqualTo("/somewhere/bar.invalid-isa.sdm"); assertThrows(IllegalArgumentException.class, () -> { ArtManagedInstallFileHelper.getTargetPathForApk("/foo/bar.abc", "/somewhere/base.apk"); diff --git a/libartservice/service/javatests/com/android/server/art/DumpHelperTest.java b/libartservice/service/javatests/com/android/server/art/DumpHelperTest.java index c063260f86..9dbecaf49c 100644 --- a/libartservice/service/javatests/com/android/server/art/DumpHelperTest.java +++ b/libartservice/service/javatests/com/android/server/art/DumpHelperTest.java @@ -80,8 +80,6 @@ public class DumpHelperTest { @Mock private SigningInfo mSigningInfoA; @Mock private SigningInfo mSigningInfoB; - private DumpHelper mDumpHelper; - @Before public void setUp() throws Exception { lenient().when(Constants.getPreferredAbi()).thenReturn("arm64-v8a"); @@ -112,8 +110,6 @@ public class DumpHelperTest { lenient().when(mSigningInfoA.signersMatchExactly(mSigningInfoB)).thenReturn(false); lenient().when(mSigningInfoB.signersMatchExactly(mSigningInfoB)).thenReturn(true); lenient().when(mSigningInfoB.signersMatchExactly(mSigningInfoA)).thenReturn(false); - - mDumpHelper = new DumpHelper(mInjector); } @Test @@ -161,7 +157,8 @@ public class DumpHelperTest { + "Current GC: CollectorTypeCMC\n"; var stringWriter = new StringWriter(); - mDumpHelper.dump(new PrintWriter(stringWriter), mSnapshot, false /* verifySdmSignatures */); + createDumpHelper(false /* verifySdmSignatures */) + .dump(new PrintWriter(stringWriter), mSnapshot); assertThat(stringWriter.toString()).isEqualTo(expected); } @@ -170,73 +167,110 @@ public class DumpHelperTest { when(mInjector.fileExists(any())).thenReturn(false); var stringWriter = new StringWriter(); - mDumpHelper.dumpPackage(new PrintWriter(stringWriter), mSnapshot, - getPackageState(PKG_NAME_BAR), true /* verifySdmSignatures */); + createDumpHelper(true /* verifySdmSignatures */) + .dumpPackage( + new PrintWriter(stringWriter), mSnapshot, getPackageState(PKG_NAME_BAR)); assertThat(stringWriter.toString()).doesNotContain("sdm:"); } @Test public void testDumpSdmStatusInvalidSdmSignature() throws Exception { - when(mInjector.fileExists("/somewhere/app/bar/base.sdm")).thenReturn(true); - when(mInjector.getVerifiedSigningInfo(eq("/somewhere/app/bar/base.sdm"), anyInt())) + doReturn(false).when(mInjector).fileExists("/somewhere/app/bar/base.arm.sdm"); + doReturn(true).when(mInjector).fileExists("/somewhere/app/bar/base.arm64.sdm"); + when(mInjector.getVerifiedSigningInfo(eq("/somewhere/app/bar/base.arm64.sdm"), anyInt())) .thenThrow(SigningInfoException.class); var stringWriter = new StringWriter(); - mDumpHelper.dumpPackage(new PrintWriter(stringWriter), mSnapshot, - getPackageState(PKG_NAME_BAR), true /* verifySdmSignatures */); + createDumpHelper(true /* verifySdmSignatures */) + .dumpPackage( + new PrintWriter(stringWriter), mSnapshot, getPackageState(PKG_NAME_BAR)); assertThat(stringWriter.toString()) .contains("sdm: [sdm-status=pending] [sdm-signature=invalid-sdm-signature]"); } @Test public void testDumpSdmStatusInvalidApkSignature() throws Exception { - when(mInjector.fileExists("/somewhere/app/bar/base.sdm")).thenReturn(true); + doReturn(false).when(mInjector).fileExists("/somewhere/app/bar/base.arm.sdm"); + doReturn(true).when(mInjector).fileExists("/somewhere/app/bar/base.arm64.sdm"); doReturn(mSigningInfoA) .when(mInjector) - .getVerifiedSigningInfo(eq("/somewhere/app/bar/base.sdm"), anyInt()); + .getVerifiedSigningInfo(eq("/somewhere/app/bar/base.arm64.sdm"), anyInt()); doThrow(SigningInfoException.class) .when(mInjector) .getVerifiedSigningInfo(eq("/somewhere/app/bar/base.apk"), anyInt()); var stringWriter = new StringWriter(); - mDumpHelper.dumpPackage(new PrintWriter(stringWriter), mSnapshot, - getPackageState(PKG_NAME_BAR), true /* verifySdmSignatures */); + createDumpHelper(true /* verifySdmSignatures */) + .dumpPackage( + new PrintWriter(stringWriter), mSnapshot, getPackageState(PKG_NAME_BAR)); assertThat(stringWriter.toString()) .contains("sdm: [sdm-status=pending] [sdm-signature=invalid-apk-signature]"); } @Test public void testDumpSdmStatusSignersNotMatch() throws Exception { - when(mInjector.fileExists("/somewhere/app/bar/base.sdm")).thenReturn(true); + doReturn(false).when(mInjector).fileExists("/somewhere/app/bar/base.arm.sdm"); + doReturn(true).when(mInjector).fileExists("/somewhere/app/bar/base.arm64.sdm"); doReturn(mSigningInfoA) .when(mInjector) - .getVerifiedSigningInfo(eq("/somewhere/app/bar/base.sdm"), anyInt()); + .getVerifiedSigningInfo(eq("/somewhere/app/bar/base.arm64.sdm"), anyInt()); doReturn(mSigningInfoB) .when(mInjector) .getVerifiedSigningInfo(eq("/somewhere/app/bar/base.apk"), anyInt()); var stringWriter = new StringWriter(); - mDumpHelper.dumpPackage(new PrintWriter(stringWriter), mSnapshot, - getPackageState(PKG_NAME_BAR), true /* verifySdmSignatures */); + createDumpHelper(true /* verifySdmSignatures */) + .dumpPackage( + new PrintWriter(stringWriter), mSnapshot, getPackageState(PKG_NAME_BAR)); assertThat(stringWriter.toString()) .contains("sdm: [sdm-status=pending] [sdm-signature=mismatched-signers]"); } @Test public void testDumpSdmStatusVerified() throws Exception { - when(mInjector.fileExists("/somewhere/app/bar/base.sdm")).thenReturn(true); + doReturn(false).when(mInjector).fileExists("/somewhere/app/bar/base.arm.sdm"); + doReturn(true).when(mInjector).fileExists("/somewhere/app/bar/base.arm64.sdm"); doReturn(mSigningInfoA) .when(mInjector) - .getVerifiedSigningInfo(eq("/somewhere/app/bar/base.sdm"), anyInt()); + .getVerifiedSigningInfo(eq("/somewhere/app/bar/base.arm64.sdm"), anyInt()); doReturn(mSigningInfoA) .when(mInjector) .getVerifiedSigningInfo(eq("/somewhere/app/bar/base.apk"), anyInt()); var stringWriter = new StringWriter(); - mDumpHelper.dumpPackage(new PrintWriter(stringWriter), mSnapshot, - getPackageState(PKG_NAME_BAR), true /* verifySdmSignatures */); + createDumpHelper(true /* verifySdmSignatures */) + .dumpPackage( + new PrintWriter(stringWriter), mSnapshot, getPackageState(PKG_NAME_BAR)); + assertThat(stringWriter.toString()) + .containsMatch(" \\Qpath: /somewhere/app/bar/base.apk\\E\n" + + " arm:.*\n" + + " .*\n" + + " arm64:.*\n" + + " .*\n" + + " \\Qsdm: [sdm-status=pending] " + + "[sdm-signature=verified]\\E\n"); + } + + @Test + public void testDumpSdmStatusMultiArch() throws Exception { + doReturn(true).when(mInjector).fileExists("/somewhere/app/bar/base.arm.sdm"); + doReturn(true).when(mInjector).fileExists("/somewhere/app/bar/base.arm64.sdm"); + doReturn(mSigningInfoA).when(mInjector).getVerifiedSigningInfo(any(), anyInt()); + + var stringWriter = new StringWriter(); + createDumpHelper(true /* verifySdmSignatures */) + .dumpPackage( + new PrintWriter(stringWriter), mSnapshot, getPackageState(PKG_NAME_BAR)); assertThat(stringWriter.toString()) - .contains("sdm: [sdm-status=pending] [sdm-signature=verified]"); + .containsMatch(" \\Qpath: /somewhere/app/bar/base.apk\\E\n" + + " arm:.*\n" + + " .*\n" + + " \\Qsdm: [sdm-status=pending] " + + "[sdm-signature=verified]\\E\n" + + " arm64:.*\n" + + " .*\n" + + " \\Qsdm: [sdm-status=pending] " + + "[sdm-signature=verified]\\E\n"); } private PackageState createPackageState(@NonNull String packageName, int appId, boolean isApex, @@ -411,4 +445,8 @@ public class DumpHelperTest { private PackageState getPackageState(String packageName) { return mSnapshot.getPackageState(packageName); } + + private DumpHelper createDumpHelper(boolean verifySdmSignatures) { + return new DumpHelper(mInjector, verifySdmSignatures); + } } |