From 5556c5f17ab85a6e13a1da8c31ffbe16c2b800fb Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Thu, 9 Jun 2022 17:32:21 +0000 Subject: [PATCH] Treat and _compressed prebuilt APEXes as being equivalent (cherry picked from commit 1aa50564c783e4134e2fb4a7cdd0abca5b7b1403) When extracting dex files from prebuilt APEXes the build fails if it finds two or more prebuilt APEXes that could provide the dex files. This change treats and _compressed APEXes as being the same and always selects the uncompressed APEX. Bug: 235284603 Test: m nothing # Added TestDuplicateButEquivalentDeapexersFromPrebuiltApexes # Failed without this change, works with it. Merged-In: I805cb9dfa9f590c91585d75c4f4586b212b73d41 Change-Id: I805cb9dfa9f590c91585d75c4f4586b212b73d41 --- android/deapexer.go | 43 +++++++++++++++++- apex/apex_test.go | 103 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 143 insertions(+), 3 deletions(-) diff --git a/android/deapexer.go b/android/deapexer.go index 265f5312b..6a93f6087 100644 --- a/android/deapexer.go +++ b/android/deapexer.go @@ -15,6 +15,8 @@ package android import ( + "strings" + "github.com/google/blueprint" ) @@ -148,12 +150,19 @@ type RequiresFilesFromPrebuiltApexTag interface { func FindDeapexerProviderForModule(ctx ModuleContext) *DeapexerInfo { var di *DeapexerInfo ctx.VisitDirectDepsWithTag(DeapexerTag, func(m Module) { - p := ctx.OtherModuleProvider(m, DeapexerProvider).(DeapexerInfo) + c := ctx.OtherModuleProvider(m, DeapexerProvider).(DeapexerInfo) + p := &c if di != nil { + // If two DeapexerInfo providers have been found then check if they are + // equivalent. If they are then use the selected one, otherwise fail. + if selected := equivalentDeapexerInfoProviders(di, p); selected != nil { + di = selected + return + } ctx.ModuleErrorf("Multiple installable prebuilt APEXes provide ambiguous deapexers: %s and %s", di.ApexModuleName(), p.ApexModuleName()) } - di = &p + di = p }) if di != nil { return di @@ -162,3 +171,33 @@ func FindDeapexerProviderForModule(ctx ModuleContext) *DeapexerInfo { ctx.ModuleErrorf("No prebuilt APEX provides a deapexer module for APEX variant %s", ai.ApexVariationName) return nil } + +// removeCompressedApexSuffix removes the _compressed suffix from the name if present. +func removeCompressedApexSuffix(name string) string { + return strings.TrimSuffix(name, "_compressed") +} + +// equivalentDeapexerInfoProviders checks to make sure that the two DeapexerInfo structures are +// equivalent. +// +// At the moment and _compressed APEXes are treated as being equivalent. +// +// If they are not equivalent then this returns nil, otherwise, this returns the DeapexerInfo that +// should be used by the build, which is always the uncompressed one. That ensures that the behavior +// of the build is not dependent on which prebuilt APEX is visited first. +func equivalentDeapexerInfoProviders(p1 *DeapexerInfo, p2 *DeapexerInfo) *DeapexerInfo { + n1 := removeCompressedApexSuffix(p1.ApexModuleName()) + n2 := removeCompressedApexSuffix(p2.ApexModuleName()) + + // If the names don't match then they are not equivalent. + if n1 != n2 { + return nil + } + + // Select the uncompressed APEX. + if n1 == removeCompressedApexSuffix(n1) { + return p1 + } else { + return p2 + } +} diff --git a/apex/apex_test.go b/apex/apex_test.go index 7905710f2..dbe918010 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -7440,7 +7440,7 @@ func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.F return result.TestContext } -func TestDuplicateDeapexeresFromPrebuiltApexes(t *testing.T) { +func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) { preparers := android.GroupFixturePreparers( java.PrepareForTestWithJavaDefaultModules, PrepareForTestWithApexBuildComponents, @@ -7509,6 +7509,107 @@ func TestDuplicateDeapexeresFromPrebuiltApexes(t *testing.T) { }) } +func TestDuplicateButEquivalentDeapexersFromPrebuiltApexes(t *testing.T) { + preparers := android.GroupFixturePreparers( + java.PrepareForTestWithJavaDefaultModules, + PrepareForTestWithApexBuildComponents, + ) + + bpBase := ` + apex_set { + name: "com.android.myapex", + installable: true, + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + set: "myapex.apks", + } + + apex_set { + name: "com.android.myapex_compressed", + apex_name: "com.android.myapex", + installable: true, + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + set: "myapex_compressed.apks", + } + + prebuilt_bootclasspath_fragment { + name: "my-bootclasspath-fragment", + apex_available: [ + "com.android.myapex", + "com.android.myapex_compressed", + ], + hidden_api: { + annotation_flags: "annotation-flags.csv", + metadata: "metadata.csv", + index: "index.csv", + signature_patterns: "signature_patterns.csv", + }, + %s + } + ` + + t.Run("java_import", func(t *testing.T) { + result := preparers.RunTestWithBp(t, + fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+` + java_import { + name: "libfoo", + jars: ["libfoo.jar"], + apex_available: [ + "com.android.myapex", + "com.android.myapex_compressed", + ], + } + `) + + module := result.Module("libfoo", "android_common_com.android.myapex") + usesLibraryDep := module.(java.UsesLibraryDependency) + android.AssertPathRelativeToTopEquals(t, "dex jar path", + "out/soong/.intermediates/com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar", + usesLibraryDep.DexJarBuildPath().Path()) + }) + + t.Run("java_sdk_library_import", func(t *testing.T) { + result := preparers.RunTestWithBp(t, + fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+` + java_sdk_library_import { + name: "libfoo", + public: { + jars: ["libbar.jar"], + }, + apex_available: [ + "com.android.myapex", + "com.android.myapex_compressed", + ], + compile_dex: true, + } + `) + + module := result.Module("libfoo", "android_common_com.android.myapex") + usesLibraryDep := module.(java.UsesLibraryDependency) + android.AssertPathRelativeToTopEquals(t, "dex jar path", + "out/soong/.intermediates/com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar", + usesLibraryDep.DexJarBuildPath().Path()) + }) + + t.Run("prebuilt_bootclasspath_fragment", func(t *testing.T) { + _ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, ` + image_name: "art", + contents: ["libfoo"], + `)+` + java_sdk_library_import { + name: "libfoo", + public: { + jars: ["libbar.jar"], + }, + apex_available: [ + "com.android.myapex", + "com.android.myapex_compressed", + ], + compile_dex: true, + } + `) + }) +} + func TestUpdatable_should_set_min_sdk_version(t *testing.T) { testApexError(t, `"myapex" .*: updatable: updatable APEXes should set min_sdk_version`, ` apex {