diff options
author | 2024-05-18 02:03:18 +0100 | |
---|---|---|
committer | 2024-05-23 18:07:55 +0000 | |
commit | 490e26f66c95b0d103c05573c46ff3322ba99e85 (patch) | |
tree | 3a9ae987af941b380d24772aa7fea7096c298d29 | |
parent | b7ab61a7597b58e91f51b91e7c99e306cf8fdabb (diff) |
Skip non-existing dex files.
Bug: 311377497
Test: atest ArtServiceTests
Change-Id: Ib7aa2fe55c3652a83439417eae85eddf9eca25a2
5 files changed, 76 insertions, 0 deletions
diff --git a/libartservice/service/java/com/android/server/art/Dexopter.java b/libartservice/service/java/com/android/server/art/Dexopter.java index b8aa912723..5185f59b20 100644 --- a/libartservice/service/java/com/android/server/art/Dexopter.java +++ b/libartservice/service/java/com/android/server/art/Dexopter.java @@ -118,6 +118,14 @@ public abstract class Dexopter<DexInfoType extends DetailedDexInfo> { continue; } + if (mInjector.isPreReboot() && !isDexFileFound(dexInfo)) { + // In the pre-reboot case, it's possible that a dex file doesn't exist in the + // new system image. Although code below can gracefully handle failures, those + // failures can be red herrings in metrics and bug reports, so we skip + // non-existing dex files to avoid them. + continue; + } + DexMetadataInfo dmInfo = mInjector.getDexMetadataHelper().getDexMetadataInfo(buildDmPath(dexInfo)); @@ -639,6 +647,11 @@ public abstract class Dexopter<DexInfoType extends DetailedDexInfo> { protected abstract boolean isDexFilePublic(@NonNull DexInfoType dexInfo); /** + * Returns true if the dex file is found. + */ + protected abstract boolean isDexFileFound(@NonNull DexInfoType dexInfo); + + /** * Returns a list of external profiles (e.g., a DM profile) that the reference profile can be * initialized from, in the order of preference. */ diff --git a/libartservice/service/java/com/android/server/art/PrimaryDexopter.java b/libartservice/service/java/com/android/server/art/PrimaryDexopter.java index e4475d8503..f8234c4df9 100644 --- a/libartservice/service/java/com/android/server/art/PrimaryDexopter.java +++ b/libartservice/service/java/com/android/server/art/PrimaryDexopter.java @@ -118,6 +118,17 @@ public class PrimaryDexopter extends Dexopter<DetailedPrimaryDexInfo> { } @Override + protected boolean isDexFileFound(@NonNull DetailedPrimaryDexInfo dexInfo) { + try { + return mInjector.getArtd().getDexFileVisibility(dexInfo.dexPath()) + != FileVisibility.NOT_FOUND; + } catch (ServiceSpecificException | RemoteException e) { + AsLog.e("Failed to get visibility of " + dexInfo.dexPath(), e); + return false; + } + } + + @Override @NonNull protected List<ProfilePath> getExternalProfiles(@NonNull DetailedPrimaryDexInfo dexInfo) { return PrimaryDexUtils.getExternalProfiles(dexInfo); diff --git a/libartservice/service/java/com/android/server/art/SecondaryDexopter.java b/libartservice/service/java/com/android/server/art/SecondaryDexopter.java index 07c6c0d654..57fe174d6a 100644 --- a/libartservice/service/java/com/android/server/art/SecondaryDexopter.java +++ b/libartservice/service/java/com/android/server/art/SecondaryDexopter.java @@ -87,6 +87,12 @@ public class SecondaryDexopter extends Dexopter<CheckedSecondaryDexInfo> { } @Override + protected boolean isDexFileFound(@NonNull CheckedSecondaryDexInfo dexInfo) { + // `getDexInfoList` has already excluded non-existing dex files. + return true; + } + + @Override @NonNull protected List<ProfilePath> getExternalProfiles(@NonNull CheckedSecondaryDexInfo dexInfo) { // A secondary dex file doesn't have any external profile to use. diff --git a/libartservice/service/javatests/com/android/server/art/PrimaryDexopterParameterizedTest.java b/libartservice/service/javatests/com/android/server/art/PrimaryDexopterParameterizedTest.java index 864390c217..2304d5c180 100644 --- a/libartservice/service/javatests/com/android/server/art/PrimaryDexopterParameterizedTest.java +++ b/libartservice/service/javatests/com/android/server/art/PrimaryDexopterParameterizedTest.java @@ -311,6 +311,15 @@ public class PrimaryDexopterParameterizedTest extends PrimaryDexopterTestBase { .when(mDexMetadataHelperInjector.openZipFile(any())) .thenThrow(NoSuchFileException.class); + if (mParams.mIsPreReboot) { + doReturn(FileVisibility.OTHER_READABLE) + .when(mArtd) + .getDexFileVisibility("/somewhere/app/foo/base.apk"); + doReturn(FileVisibility.OTHER_READABLE) + .when(mArtd) + .getDexFileVisibility("/somewhere/app/foo/split_0.apk"); + } + // The first one is normal. doReturn(dexoptIsNeeded()) .when(mArtd) diff --git a/libartservice/service/javatests/com/android/server/art/PrimaryDexopterTest.java b/libartservice/service/javatests/com/android/server/art/PrimaryDexopterTest.java index beb8c1eaf4..eb90b49e4a 100644 --- a/libartservice/service/javatests/com/android/server/art/PrimaryDexopterTest.java +++ b/libartservice/service/javatests/com/android/server/art/PrimaryDexopterTest.java @@ -140,6 +140,13 @@ public class PrimaryDexopterTest extends PrimaryDexopterTestBase { .when(mArtd.createCancellationSignal()) .thenReturn(mock(IArtdCancellationSignal.class)); + lenient() + .when(mArtd.getDexFileVisibility(mDexPath)) + .thenReturn(FileVisibility.OTHER_READABLE); + lenient() + .when(mArtd.getDexFileVisibility(mSplit0DexPath)) + .thenReturn(FileVisibility.OTHER_READABLE); + mPrimaryDexopter = new PrimaryDexopter(mInjector, mPkgState, mPkg, mDexoptParams, mCancellationSignal); @@ -850,6 +857,36 @@ public class PrimaryDexopterTest extends PrimaryDexopterTestBase { .isEqualTo(0); } + @Test + public void testDexoptPreRebootDexNotFound() throws Exception { + when(mInjector.isPreReboot()).thenReturn(true); + doReturn(FileVisibility.NOT_FOUND).when(mArtd).getDexFileVisibility(mDexPath); + doReturn(FileVisibility.NOT_FOUND).when(mArtd).getDexFileVisibility(mSplit0DexPath); + + mPrimaryDexopter = + new PrimaryDexopter(mInjector, mPkgState, mPkg, mDexoptParams, mCancellationSignal); + + List<DexContainerFileDexoptResult> results = mPrimaryDexopter.dexopt(); + assertThat(results).hasSize(0); + } + + @Test + public void testDexoptPreRebootSomeDexNotFound() throws Exception { + when(mInjector.isPreReboot()).thenReturn(true); + doReturn(FileVisibility.OTHER_READABLE).when(mArtd).getDexFileVisibility(mDexPath); + doReturn(FileVisibility.NOT_FOUND).when(mArtd).getDexFileVisibility(mSplit0DexPath); + + mPrimaryDexopter = + new PrimaryDexopter(mInjector, mPkgState, mPkg, mDexoptParams, mCancellationSignal); + + List<DexContainerFileDexoptResult> results = mPrimaryDexopter.dexopt(); + assertThat(results).hasSize(2); + assertThat(results.get(0).getDexContainerFile()).isEqualTo(mDexPath); + assertThat(results.get(0).getAbi()).isEqualTo("arm64-v8a"); + assertThat(results.get(1).getDexContainerFile()).isEqualTo(mDexPath); + assertThat(results.get(1).getAbi()).isEqualTo("armeabi-v7a"); + } + private void checkDexoptWithProfile(IArtd artd, String dexPath, String isa, ProfilePath profile, boolean isOtherReadable) throws Exception { artd.dexopt(argThat(artifacts |