diff options
Diffstat (limited to 'apex/apex_test.go')
| -rw-r--r-- | apex/apex_test.go | 1072 |
1 files changed, 799 insertions, 273 deletions
diff --git a/apex/apex_test.go b/apex/apex_test.go index abf6b1534..9dc77c28d 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -790,6 +790,79 @@ func TestApexManifestMinSdkVersion(t *testing.T) { } } +func TestApexWithDessertSha(t *testing.T) { + ctx := testApex(t, ` + apex_defaults { + name: "my_defaults", + key: "myapex.key", + product_specific: true, + file_contexts: ":my-file-contexts", + updatable: false, + } + apex { + name: "myapex_30", + min_sdk_version: "30", + defaults: ["my_defaults"], + } + + apex { + name: "myapex_current", + min_sdk_version: "current", + defaults: ["my_defaults"], + } + + apex { + name: "myapex_none", + defaults: ["my_defaults"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + filegroup { + name: "my-file-contexts", + srcs: ["product_specific_file_contexts"], + } + `, withFiles(map[string][]byte{ + "product_specific_file_contexts": nil, + }), android.FixtureModifyProductVariables( + func(variables android.FixtureProductVariables) { + variables.Unbundled_build = proptools.BoolPtr(true) + variables.Always_use_prebuilt_sdks = proptools.BoolPtr(false) + }), android.FixtureMergeEnv(map[string]string{ + "UNBUNDLED_BUILD_TARGET_SDK_WITH_DESSERT_SHA": "UpsideDownCake.abcdefghijklmnopqrstuvwxyz123456", + })) + + testCases := []struct { + module string + minSdkVersion string + }{ + { + module: "myapex_30", + minSdkVersion: "30", + }, + { + module: "myapex_current", + minSdkVersion: "UpsideDownCake.abcdefghijklmnopqrstuvwxyz123456", + }, + { + module: "myapex_none", + minSdkVersion: "UpsideDownCake.abcdefghijklmnopqrstuvwxyz123456", + }, + } + for _, tc := range testCases { + module := ctx.ModuleForTests(tc.module, "android_common_"+tc.module) + args := module.Rule("apexRule").Args + optFlags := args["opt_flags"] + if !strings.Contains(optFlags, "--min_sdk_version "+tc.minSdkVersion) { + t.Errorf("%s: Expected min_sdk_version=%s, got: %s", tc.module, tc.minSdkVersion, optFlags) + } + } +} + func TestFileContexts(t *testing.T) { for _, vendor := range []bool{true, false} { prop := "" @@ -1455,6 +1528,7 @@ func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) { name: "libc", no_libcrt: true, nocrt: true, + no_crt_pad_segment: true, stl: "none", system_shared_libs: [], stubs: { versions: ["1"] }, @@ -1469,6 +1543,7 @@ func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) { name: "libclang_rt.hwasan", no_libcrt: true, nocrt: true, + no_crt_pad_segment: true, stl: "none", system_shared_libs: [], srcs: [""], @@ -1511,6 +1586,7 @@ func TestRuntimeApexShouldInstallHwasanIfHwaddressSanitized(t *testing.T) { name: "libc", no_libcrt: true, nocrt: true, + no_crt_pad_segment: true, stl: "none", system_shared_libs: [], stubs: { versions: ["1"] }, @@ -1521,6 +1597,7 @@ func TestRuntimeApexShouldInstallHwasanIfHwaddressSanitized(t *testing.T) { name: "libclang_rt.hwasan", no_libcrt: true, nocrt: true, + no_crt_pad_segment: true, stl: "none", system_shared_libs: [], srcs: [""], @@ -3725,7 +3802,7 @@ func ensureExactContents(t *testing.T, ctx *android.TestContext, moduleName, var } func ensureExactDeapexedContents(t *testing.T, ctx *android.TestContext, moduleName string, variant string, files []string) { - deapexer := ctx.ModuleForTests(moduleName+".deapexer", variant).Rule("deapexer") + deapexer := ctx.ModuleForTests(moduleName+".deapexer", variant).Description("deapex") outputs := make([]string, 0, len(deapexer.ImplicitOutputs)+1) if deapexer.Output != nil { outputs = append(outputs, deapexer.Output.String()) @@ -3768,13 +3845,6 @@ func TestVndkApexCurrent(t *testing.T) { "lib64/libvndk.so", "lib64/libvndksp.so"), }, - { - vndkVersion: "", - expectedFiles: append(commonFiles, - // Legacy VNDK APEX contains only VNDK-SP files (of core variant) - "lib/libvndksp.so", - "lib64/libvndksp.so"), - }, } for _, tc := range testCases { t.Run("VNDK.current with DeviceVndkVersion="+tc.vndkVersion, func(t *testing.T) { @@ -4976,6 +5046,7 @@ func TestApexWithShBinary(t *testing.T) { key: "myapex.key", sh_binaries: ["myscript"], updatable: false, + compile_multilib: "both", } apex_key { @@ -5355,6 +5426,13 @@ func TestPrebuiltApexNameWithPlatformBootclasspath(t *testing.T) { ).RunTest(t) } +// A minimal context object for use with DexJarBuildPath +type moduleErrorfTestCtx struct { +} + +func (ctx moduleErrorfTestCtx) ModuleErrorf(format string, args ...interface{}) { +} + // These tests verify that the prebuilt_apex/deapexer to java_import wiring allows for the // propagation of paths to dex implementation jars from the former to the latter. func TestPrebuiltExportDexImplementationJars(t *testing.T) { @@ -5364,10 +5442,10 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) { t.Helper() // Make sure the import has been given the correct path to the dex jar. p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.UsesLibraryDependency) - dexJarBuildPath := p.DexJarBuildPath().PathOrNil() + dexJarBuildPath := p.DexJarBuildPath(moduleErrorfTestCtx{}).PathOrNil() stem := android.RemoveOptionalPrebuiltPrefix(name) android.AssertStringEquals(t, "DexJarBuildPath should be apex-related path.", - ".intermediates/myapex.deapexer/android_common/deapexer/javalib/"+stem+".jar", + ".intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/"+stem+".jar", android.NormalizePathForTesting(dexJarBuildPath)) } @@ -5421,8 +5499,8 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) { // Make sure that dexpreopt can access dex implementation files from the prebuilt. ctx := testDexpreoptWithApexes(t, bp, "", transform) - deapexerName := deapexerModuleName("myapex") - android.AssertStringEquals(t, "APEX module name from deapexer name", "myapex", apexModuleName(deapexerName)) + deapexerName := deapexerModuleName("prebuilt_myapex") + android.AssertStringEquals(t, "APEX module name from deapexer name", "prebuilt_myapex", apexModuleName(deapexerName)) // Make sure that the deapexer has the correct input APEX. deapexer := ctx.ModuleForTests(deapexerName, "android_common") @@ -5645,8 +5723,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { ` ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment) - checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") - checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar") + checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") + checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar") // Verify the correct module jars contribute to the hiddenapi index file. checkHiddenAPIIndexFromClassesInputs(t, ctx, ``) @@ -5723,8 +5801,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { ` ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment) - checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") - checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar") + checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") + checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar") // Verify the correct module jars contribute to the hiddenapi index file. checkHiddenAPIIndexFromClassesInputs(t, ctx, ``) @@ -5737,7 +5815,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { myApex := ctx.ModuleForTests("myapex", "android_common_myapex").Module() overrideNames := []string{ - "", + "myapex", "myjavalib.myapex", "libfoo.myapex", "libbar.myapex", @@ -5912,8 +5990,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { ` ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment) - checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") - checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar") + checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") + checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar") // Verify the correct module jars contribute to the hiddenapi index file. checkHiddenAPIIndexFromClassesInputs(t, ctx, ``) @@ -6109,8 +6187,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { ` ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment) - checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") - checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar") + checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") + checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar") // Verify the correct module jars contribute to the hiddenapi index file. checkHiddenAPIIndexFromClassesInputs(t, ctx, ``) @@ -6120,6 +6198,84 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv `) }) + + t.Run("Co-existing unflagged apexes should create a duplicate module error", func(t *testing.T) { + bp := ` + // Source + apex { + name: "myapex", + enabled: false, + key: "myapex.key", + bootclasspath_fragments: ["my-bootclasspath-fragment"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + // Prebuilt + prebuilt_apex { + name: "myapex.v1", + source_apex_name: "myapex", + arch: { + arm64: { + src: "myapex-arm64.apex", + }, + arm: { + src: "myapex-arm.apex", + }, + }, + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + prefer: true, + } + prebuilt_apex { + name: "myapex.v2", + source_apex_name: "myapex", + arch: { + arm64: { + src: "myapex-arm64.apex", + }, + arm: { + src: "myapex-arm.apex", + }, + }, + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + prefer: true, + } + + prebuilt_bootclasspath_fragment { + name: "my-bootclasspath-fragment", + contents: ["libfoo", "libbar"], + apex_available: ["myapex"], + hidden_api: { + annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv", + metadata: "my-bootclasspath-fragment/metadata.csv", + index: "my-bootclasspath-fragment/index.csv", + stub_flags: "my-bootclasspath-fragment/stub-flags.csv", + all_flags: "my-bootclasspath-fragment/all-flags.csv", + }, + prefer: true, + } + + java_import { + name: "libfoo", + jars: ["libfoo.jar"], + apex_available: ["myapex"], + prefer: true, + } + java_import { + name: "libbar", + jars: ["libbar.jar"], + apex_available: ["myapex"], + prefer: true, + } + ` + + testDexpreoptWithApexes(t, bp, "Multiple prebuilt modules prebuilt_myapex.v1 and prebuilt_myapex.v2 have been marked as preferred for this source module", preparer, fragment) + }) + } func TestApexWithTests(t *testing.T) { @@ -8313,9 +8469,9 @@ func TestAppSetBundlePrebuilt(t *testing.T) { ctx := testApex(t, bp, prepareForTestWithSantitizeHwaddress) // Check that the extractor produces the correct output file from the correct input file. - extractorOutput := "out/soong/.intermediates/myapex.apex.extractor/android_common/extracted/myapex.hwasan.apks" + extractorOutput := "out/soong/.intermediates/prebuilt_myapex.apex.extractor/android_common/extracted/myapex.hwasan.apks" - m := ctx.ModuleForTests("myapex.apex.extractor", "android_common") + m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common") extractedApex := m.Output(extractorOutput) android.AssertArrayString(t, "extractor input", []string{"myapex.hwasan.apks"}, extractedApex.Inputs.Strings()) @@ -8340,10 +8496,10 @@ func TestApexSetApksModuleAssignment(t *testing.T) { } `) - m := ctx.ModuleForTests("myapex.apex.extractor", "android_common") + m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common") // Check that the extractor produces the correct apks file from the input module - extractorOutput := "out/soong/.intermediates/myapex.apex.extractor/android_common/extracted/myapex.apks" + extractorOutput := "out/soong/.intermediates/prebuilt_myapex.apex.extractor/android_common/extracted/myapex.apks" extractedApex := m.Output(extractorOutput) android.AssertArrayString(t, "extractor input", []string{"myapex.apks"}, extractedApex.Inputs.Strings()) @@ -8408,30 +8564,39 @@ func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.F func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) { preparers := android.GroupFixturePreparers( java.PrepareForTestWithJavaDefaultModules, + prepareForTestWithBootclasspathFragment, + dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:libfoo"), PrepareForTestWithApexBuildComponents, ). ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( - "Multiple installable prebuilt APEXes provide ambiguous deapexers: com.android.myapex and com.mycompany.android.myapex")) + "Multiple installable prebuilt APEXes provide ambiguous deapexers: prebuilt_com.android.art and prebuilt_com.mycompany.android.art")) bpBase := ` apex_set { - name: "com.android.myapex", + name: "com.android.art", installable: true, - exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + exported_bootclasspath_fragments: ["art-bootclasspath-fragment"], set: "myapex.apks", } apex_set { - name: "com.mycompany.android.myapex", - apex_name: "com.android.myapex", + name: "com.mycompany.android.art", + apex_name: "com.android.art", installable: true, - exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + exported_bootclasspath_fragments: ["art-bootclasspath-fragment"], set: "company-myapex.apks", } prebuilt_bootclasspath_fragment { - name: "my-bootclasspath-fragment", - apex_available: ["com.android.myapex"], + name: "art-bootclasspath-fragment", + apex_available: ["com.android.art"], + hidden_api: { + annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv", + metadata: "my-bootclasspath-fragment/metadata.csv", + index: "my-bootclasspath-fragment/index.csv", + stub_flags: "my-bootclasspath-fragment/stub-flags.csv", + all_flags: "my-bootclasspath-fragment/all-flags.csv", + }, %s } ` @@ -8441,7 +8606,7 @@ func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) { java_import { name: "libfoo", jars: ["libfoo.jar"], - apex_available: ["com.android.myapex"], + apex_available: ["com.android.art"], } `) }) @@ -8453,7 +8618,8 @@ func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) { public: { jars: ["libbar.jar"], }, - apex_available: ["com.android.myapex"], + shared_library: false, + apex_available: ["com.android.art"], } `) }) @@ -8468,7 +8634,8 @@ func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) { public: { jars: ["libbar.jar"], }, - apex_available: ["com.android.myapex"], + shared_library: false, + apex_available: ["com.android.art"], } `) }) @@ -8480,6 +8647,8 @@ func TestDuplicateButEquivalentDeapexersFromPrebuiltApexes(t *testing.T) { PrepareForTestWithApexBuildComponents, ) + errCtx := moduleErrorfTestCtx{} + bpBase := ` apex_set { name: "com.android.myapex", @@ -8528,8 +8697,8 @@ func TestDuplicateButEquivalentDeapexersFromPrebuiltApexes(t *testing.T) { 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()) + "out/soong/.intermediates/prebuilt_com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar", + usesLibraryDep.DexJarBuildPath(errCtx).Path()) }) t.Run("java_sdk_library_import", func(t *testing.T) { @@ -8551,8 +8720,8 @@ func TestDuplicateButEquivalentDeapexersFromPrebuiltApexes(t *testing.T) { 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()) + "out/soong/.intermediates/prebuilt_com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar", + usesLibraryDep.DexJarBuildPath(errCtx).Path()) }) t.Run("prebuilt_bootclasspath_fragment", func(t *testing.T) { @@ -9124,7 +9293,7 @@ func TestApexSet(t *testing.T) { }), ) - m := ctx.ModuleForTests("myapex.apex.extractor", "android_common") + m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common") // Check extract_apks tool parameters. extractedApex := m.Output("extracted/myapex.apks") @@ -9165,7 +9334,7 @@ func TestApexSet_NativeBridge(t *testing.T) { }), ) - m := ctx.ModuleForTests("myapex.apex.extractor", "android_common") + m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common") // Check extract_apks tool parameters. No native bridge arch expected extractedApex := m.Output("extracted/myapex.apks") @@ -10175,188 +10344,196 @@ func ensureDoesNotContainRequiredDeps(t *testing.T, ctx *android.TestContext, mo } } -// TODO(b/193460475): Re-enable this test -//func TestApexStrictUpdtabilityLint(t *testing.T) { -// bpTemplate := ` -// apex { -// name: "myapex", -// key: "myapex.key", -// java_libs: ["myjavalib"], -// updatable: %v, -// min_sdk_version: "29", -// } -// apex_key { -// name: "myapex.key", -// } -// java_library { -// name: "myjavalib", -// srcs: ["MyClass.java"], -// apex_available: [ "myapex" ], -// lint: { -// strict_updatability_linting: %v, -// }, -// sdk_version: "current", -// min_sdk_version: "29", -// } -// ` -// fs := android.MockFS{ -// "lint-baseline.xml": nil, -// } -// -// testCases := []struct { -// testCaseName string -// apexUpdatable bool -// javaStrictUpdtabilityLint bool -// lintFileExists bool -// disallowedFlagExpected bool -// }{ -// { -// testCaseName: "lint-baseline.xml does not exist, no disallowed flag necessary in lint cmd", -// apexUpdatable: true, -// javaStrictUpdtabilityLint: true, -// lintFileExists: false, -// disallowedFlagExpected: false, -// }, -// { -// testCaseName: "non-updatable apex respects strict_updatability of javalib", -// apexUpdatable: false, -// javaStrictUpdtabilityLint: false, -// lintFileExists: true, -// disallowedFlagExpected: false, -// }, -// { -// testCaseName: "non-updatable apex respects strict updatability of javalib", -// apexUpdatable: false, -// javaStrictUpdtabilityLint: true, -// lintFileExists: true, -// disallowedFlagExpected: true, -// }, -// { -// testCaseName: "updatable apex sets strict updatability of javalib to true", -// apexUpdatable: true, -// javaStrictUpdtabilityLint: false, // will be set to true by mutator -// lintFileExists: true, -// disallowedFlagExpected: true, -// }, -// } -// -// for _, testCase := range testCases { -// bp := fmt.Sprintf(bpTemplate, testCase.apexUpdatable, testCase.javaStrictUpdtabilityLint) -// fixtures := []android.FixturePreparer{} -// if testCase.lintFileExists { -// fixtures = append(fixtures, fs.AddToFixture()) -// } -// -// result := testApex(t, bp, fixtures...) -// myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29") -// sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto")) -// disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi") -// -// if disallowedFlagActual != testCase.disallowedFlagExpected { -// t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command) -// } -// } -//} -// -//func TestUpdatabilityLintSkipLibcore(t *testing.T) { -// bp := ` -// apex { -// name: "myapex", -// key: "myapex.key", -// java_libs: ["myjavalib"], -// updatable: true, -// min_sdk_version: "29", -// } -// apex_key { -// name: "myapex.key", -// } -// java_library { -// name: "myjavalib", -// srcs: ["MyClass.java"], -// apex_available: [ "myapex" ], -// sdk_version: "current", -// min_sdk_version: "29", -// } -// ` -// -// testCases := []struct { -// testCaseName string -// moduleDirectory string -// disallowedFlagExpected bool -// }{ -// { -// testCaseName: "lintable module defined outside libcore", -// moduleDirectory: "", -// disallowedFlagExpected: true, -// }, -// { -// testCaseName: "lintable module defined in libcore root directory", -// moduleDirectory: "libcore/", -// disallowedFlagExpected: false, -// }, -// { -// testCaseName: "lintable module defined in libcore child directory", -// moduleDirectory: "libcore/childdir/", -// disallowedFlagExpected: true, -// }, -// } -// -// for _, testCase := range testCases { -// lintFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"lint-baseline.xml", "") -// bpFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"Android.bp", bp) -// result := testApex(t, "", lintFileCreator, bpFileCreator) -// myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29") -// sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto")) -// cmdFlags := fmt.Sprintf("--baseline %vlint-baseline.xml --disallowed_issues NewApi", testCase.moduleDirectory) -// disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, cmdFlags) -// -// if disallowedFlagActual != testCase.disallowedFlagExpected { -// t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command) -// } -// } -//} -// -//// checks transtive deps of an apex coming from bootclasspath_fragment -//func TestApexStrictUpdtabilityLintBcpFragmentDeps(t *testing.T) { -// bp := ` -// apex { -// name: "myapex", -// key: "myapex.key", -// bootclasspath_fragments: ["mybootclasspathfragment"], -// updatable: true, -// min_sdk_version: "29", -// } -// apex_key { -// name: "myapex.key", -// } -// bootclasspath_fragment { -// name: "mybootclasspathfragment", -// contents: ["myjavalib"], -// apex_available: ["myapex"], -// hidden_api: { -// split_packages: ["*"], -// }, -// } -// java_library { -// name: "myjavalib", -// srcs: ["MyClass.java"], -// apex_available: [ "myapex" ], -// sdk_version: "current", -// min_sdk_version: "29", -// compile_dex: true, -// } -// ` -// fs := android.MockFS{ -// "lint-baseline.xml": nil, -// } -// -// result := testApex(t, bp, dexpreopt.FixtureSetApexBootJars("myapex:myjavalib"), fs.AddToFixture()) -// myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29") -// sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto")) -// if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi") { -// t.Errorf("Strict updabality lint missing in myjavalib coming from bootclasspath_fragment mybootclasspath-fragment\nActual lint cmd: %v", *sboxProto.Commands[0].Command) -// } -//} +func TestApexStrictUpdtabilityLint(t *testing.T) { + bpTemplate := ` + apex { + name: "myapex", + key: "myapex.key", + java_libs: ["myjavalib"], + updatable: %v, + min_sdk_version: "29", + } + apex_key { + name: "myapex.key", + } + java_library { + name: "myjavalib", + srcs: ["MyClass.java"], + apex_available: [ "myapex" ], + lint: { + strict_updatability_linting: %v, + %s + }, + sdk_version: "current", + min_sdk_version: "29", + } + ` + fs := android.MockFS{ + "lint-baseline.xml": nil, + } + + testCases := []struct { + testCaseName string + apexUpdatable bool + javaStrictUpdtabilityLint bool + lintFileExists bool + disallowedFlagExpected bool + }{ + { + testCaseName: "lint-baseline.xml does not exist, no disallowed flag necessary in lint cmd", + apexUpdatable: true, + javaStrictUpdtabilityLint: true, + lintFileExists: false, + disallowedFlagExpected: false, + }, + { + testCaseName: "non-updatable apex respects strict_updatability of javalib", + apexUpdatable: false, + javaStrictUpdtabilityLint: false, + lintFileExists: true, + disallowedFlagExpected: false, + }, + { + testCaseName: "non-updatable apex respects strict updatability of javalib", + apexUpdatable: false, + javaStrictUpdtabilityLint: true, + lintFileExists: true, + disallowedFlagExpected: true, + }, + { + testCaseName: "updatable apex sets strict updatability of javalib to true", + apexUpdatable: true, + javaStrictUpdtabilityLint: false, // will be set to true by mutator + lintFileExists: true, + disallowedFlagExpected: true, + }, + } + + for _, testCase := range testCases { + fixtures := []android.FixturePreparer{} + baselineProperty := "" + if testCase.lintFileExists { + fixtures = append(fixtures, fs.AddToFixture()) + baselineProperty = "baseline_filename: \"lint-baseline.xml\"" + } + bp := fmt.Sprintf(bpTemplate, testCase.apexUpdatable, testCase.javaStrictUpdtabilityLint, baselineProperty) + + result := testApex(t, bp, fixtures...) + myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29") + sboxProto := android.RuleBuilderSboxProtoForTests(t, result, myjavalib.Output("lint.sbox.textproto")) + disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi") + + if disallowedFlagActual != testCase.disallowedFlagExpected { + t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command) + } + } +} + +func TestUpdatabilityLintSkipLibcore(t *testing.T) { + bp := ` + apex { + name: "myapex", + key: "myapex.key", + java_libs: ["myjavalib"], + updatable: true, + min_sdk_version: "29", + } + apex_key { + name: "myapex.key", + } + java_library { + name: "myjavalib", + srcs: ["MyClass.java"], + apex_available: [ "myapex" ], + sdk_version: "current", + min_sdk_version: "29", + lint: { + baseline_filename: "lint-baseline.xml", + } + } + ` + + testCases := []struct { + testCaseName string + moduleDirectory string + disallowedFlagExpected bool + }{ + { + testCaseName: "lintable module defined outside libcore", + moduleDirectory: "", + disallowedFlagExpected: true, + }, + { + testCaseName: "lintable module defined in libcore root directory", + moduleDirectory: "libcore/", + disallowedFlagExpected: false, + }, + { + testCaseName: "lintable module defined in libcore child directory", + moduleDirectory: "libcore/childdir/", + disallowedFlagExpected: true, + }, + } + + for _, testCase := range testCases { + lintFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"lint-baseline.xml", "") + bpFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"Android.bp", bp) + result := testApex(t, "", lintFileCreator, bpFileCreator) + myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29") + sboxProto := android.RuleBuilderSboxProtoForTests(t, result, myjavalib.Output("lint.sbox.textproto")) + cmdFlags := fmt.Sprintf("--baseline %vlint-baseline.xml --disallowed_issues NewApi", testCase.moduleDirectory) + disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, cmdFlags) + + if disallowedFlagActual != testCase.disallowedFlagExpected { + t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command) + } + } +} + +// checks transtive deps of an apex coming from bootclasspath_fragment +func TestApexStrictUpdtabilityLintBcpFragmentDeps(t *testing.T) { + bp := ` + apex { + name: "myapex", + key: "myapex.key", + bootclasspath_fragments: ["mybootclasspathfragment"], + updatable: true, + min_sdk_version: "29", + } + apex_key { + name: "myapex.key", + } + bootclasspath_fragment { + name: "mybootclasspathfragment", + contents: ["myjavalib"], + apex_available: ["myapex"], + hidden_api: { + split_packages: ["*"], + }, + } + java_library { + name: "myjavalib", + srcs: ["MyClass.java"], + apex_available: [ "myapex" ], + sdk_version: "current", + min_sdk_version: "29", + compile_dex: true, + lint: { + baseline_filename: "lint-baseline.xml", + } + } + ` + fs := android.MockFS{ + "lint-baseline.xml": nil, + } + + result := testApex(t, bp, dexpreopt.FixtureSetApexBootJars("myapex:myjavalib"), fs.AddToFixture()) + myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29") + sboxProto := android.RuleBuilderSboxProtoForTests(t, result, myjavalib.Output("lint.sbox.textproto")) + if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi") { + t.Errorf("Strict updabality lint missing in myjavalib coming from bootclasspath_fragment mybootclasspath-fragment\nActual lint cmd: %v", *sboxProto.Commands[0].Command) + } +} // updatable apexes should propagate updatable=true to its apps func TestUpdatableApexEnforcesAppUpdatability(t *testing.T) { @@ -10947,25 +11124,23 @@ func TestAconfigFilesJavaDeps(t *testing.T) { mod := ctx.ModuleForTests("myapex", "android_common_myapex") s := mod.Rule("apexRule").Args["copy_commands"] copyCmds := regexp.MustCompile(" *&& *").Split(s, -1) - if len(copyCmds) != 5 { + if len(copyCmds) != 8 { t.Fatalf("Expected 5 commands, got %d in:\n%s", len(copyCmds), s) } - ensureMatches(t, copyCmds[4], "^cp -f .*/aconfig_flags.pb .*/image.apex$") + ensureMatches(t, copyCmds[4], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$") + ensureMatches(t, copyCmds[5], "^cp -f .*/package.map .*/image.apex/etc$") + ensureMatches(t, copyCmds[6], "^cp -f .*/flag.map .*/image.apex/etc$") + ensureMatches(t, copyCmds[7], "^cp -f .*/flag.val .*/image.apex/etc$") - combineAconfigRule := mod.Rule("All_aconfig_declarations_dump") - s = " " + combineAconfigRule.Args["cache_files"] - aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:] - if len(aconfigArgs) != 2 { - t.Fatalf("Expected 2 commands, got %d in:\n%s", len(aconfigArgs), s) + inputs := []string{ + "my_aconfig_declarations_foo/intermediate.pb", + "my_aconfig_declarations_bar/intermediate.pb", } - android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/intermediate.pb") - android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_bar/intermediate.pb") - - buildParams := combineAconfigRule.BuildParams - android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb") - android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_bar/intermediate.pb") - ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb") + VerifyAconfigRule(t, &mod, "combine_aconfig_declarations", inputs, "android_common_myapex/aconfig_flags.pb", "", "") + VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map") + VerifyAconfigRule(t, &mod, "create_aconfig_flag_map_file", inputs, "android_common_myapex/flag.map", "myapex", "flag_map") + VerifyAconfigRule(t, &mod, "create_aconfig_flag_val_file", inputs, "android_common_myapex/flag.val", "myapex", "flag_val") } func TestAconfigFilesJavaAndCcDeps(t *testing.T) { @@ -11073,30 +11248,24 @@ func TestAconfigFilesJavaAndCcDeps(t *testing.T) { mod := ctx.ModuleForTests("myapex", "android_common_myapex") s := mod.Rule("apexRule").Args["copy_commands"] copyCmds := regexp.MustCompile(" *&& *").Split(s, -1) - if len(copyCmds) != 9 { - t.Fatalf("Expected 9 commands, got %d in:\n%s", len(copyCmds), s) + if len(copyCmds) != 12 { + t.Fatalf("Expected 12 commands, got %d in:\n%s", len(copyCmds), s) } - ensureMatches(t, copyCmds[8], "^cp -f .*/aconfig_flags.pb .*/image.apex$") - - combineAconfigRule := mod.Rule("All_aconfig_declarations_dump") - s = " " + combineAconfigRule.Args["cache_files"] - aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:] - if len(aconfigArgs) != 3 { - t.Fatalf("Expected 3 commands, got %d in:\n%s", len(aconfigArgs), s) - } - android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/intermediate.pb") - android.EnsureListContainsSuffix(t, aconfigArgs, "my_cc_library_bar/android_arm64_armv8-a_shared_apex10000/aconfig_merged.pb") - android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_baz/intermediate.pb") + ensureMatches(t, copyCmds[8], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$") + ensureMatches(t, copyCmds[9], "^cp -f .*/package.map .*/image.apex/etc$") + ensureMatches(t, copyCmds[10], "^cp -f .*/flag.map .*/image.apex/etc$") + ensureMatches(t, copyCmds[11], "^cp -f .*/flag.val .*/image.apex/etc$") - buildParams := combineAconfigRule.BuildParams - if len(buildParams.Inputs) != 3 { - t.Fatalf("Expected 3 input, got %d", len(buildParams.Inputs)) + inputs := []string{ + "my_aconfig_declarations_foo/intermediate.pb", + "my_cc_library_bar/android_arm64_armv8-a_shared_apex10000/myapex/aconfig_merged.pb", + "my_aconfig_declarations_baz/intermediate.pb", } - android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb") - android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_cc_library_bar/android_arm64_armv8-a_shared_apex10000/aconfig_merged.pb") - android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_baz/intermediate.pb") - ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb") + VerifyAconfigRule(t, &mod, "combine_aconfig_declarations", inputs, "android_common_myapex/aconfig_flags.pb", "", "") + VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map") + VerifyAconfigRule(t, &mod, "create_aconfig_flag_map_file", inputs, "android_common_myapex/flag.map", "myapex", "flag_map") + VerifyAconfigRule(t, &mod, "create_aconfig_flag_val_file", inputs, "android_common_myapex/flag.val", "myapex", "flag_val") } func TestAconfigFilesRustDeps(t *testing.T) { @@ -11220,28 +11389,45 @@ func TestAconfigFilesRustDeps(t *testing.T) { mod := ctx.ModuleForTests("myapex", "android_common_myapex") s := mod.Rule("apexRule").Args["copy_commands"] copyCmds := regexp.MustCompile(" *&& *").Split(s, -1) - if len(copyCmds) != 23 { - t.Fatalf("Expected 23 commands, got %d in:\n%s", len(copyCmds), s) + if len(copyCmds) != 26 { + t.Fatalf("Expected 26 commands, got %d in:\n%s", len(copyCmds), s) } - ensureMatches(t, copyCmds[22], "^cp -f .*/aconfig_flags.pb .*/image.apex$") + ensureMatches(t, copyCmds[22], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$") + ensureMatches(t, copyCmds[23], "^cp -f .*/package.map .*/image.apex/etc$") + ensureMatches(t, copyCmds[24], "^cp -f .*/flag.map .*/image.apex/etc$") + ensureMatches(t, copyCmds[25], "^cp -f .*/flag.val .*/image.apex/etc$") - combineAconfigRule := mod.Rule("All_aconfig_declarations_dump") - s = " " + combineAconfigRule.Args["cache_files"] + inputs := []string{ + "my_aconfig_declarations_foo/intermediate.pb", + "my_aconfig_declarations_bar/intermediate.pb", + "my_aconfig_declarations_baz/intermediate.pb", + "my_rust_binary/android_arm64_armv8-a_apex10000/myapex/aconfig_merged.pb", + } + VerifyAconfigRule(t, &mod, "combine_aconfig_declarations", inputs, "android_common_myapex/aconfig_flags.pb", "", "") + VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map") + VerifyAconfigRule(t, &mod, "create_aconfig_flag_map_file", inputs, "android_common_myapex/flag.map", "myapex", "flag_map") + VerifyAconfigRule(t, &mod, "create_aconfig_flag_val_file", inputs, "android_common_myapex/flag.val", "myapex", "flag_val") +} + +func VerifyAconfigRule(t *testing.T, mod *android.TestingModule, desc string, inputs []string, output string, container string, file_type string) { + aconfigRule := mod.Description(desc) + s := " " + aconfigRule.Args["cache_files"] aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:] - if len(aconfigArgs) != 2 { - t.Fatalf("Expected 2 commands, got %d in:\n%s", len(aconfigArgs), s) + if len(aconfigArgs) != len(inputs) { + t.Fatalf("Expected %d commands, got %d in:\n%s", len(inputs), len(aconfigArgs), s) } - android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/intermediate.pb") - android.EnsureListContainsSuffix(t, aconfigArgs, "my_rust_binary/android_arm64_armv8-a_apex10000/aconfig_merged.pb") - buildParams := combineAconfigRule.BuildParams - if len(buildParams.Inputs) != 2 { - t.Fatalf("Expected 3 input, got %d", len(buildParams.Inputs)) + ensureEquals(t, container, aconfigRule.Args["container"]) + ensureEquals(t, file_type, aconfigRule.Args["file_type"]) + + buildParams := aconfigRule.BuildParams + for _, input := range inputs { + android.EnsureListContainsSuffix(t, aconfigArgs, input) + android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), input) } - android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb") - android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_rust_binary/android_arm64_armv8-a_apex10000/aconfig_merged.pb") - ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb") + + ensureContains(t, buildParams.Output.String(), output) } func TestAconfigFilesOnlyMatchCurrentApex(t *testing.T) { @@ -11404,3 +11590,343 @@ func TestAconfigFilesRemoveDuplicates(t *testing.T) { android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb") ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb") } + +// Test that the boot jars come from the _selected_ apex prebuilt +// RELEASE_APEX_CONTIRBUTIONS_* build flags will be used to select the correct prebuilt for a specific release config +func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) { + checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) { + t.Helper() + s := ctx.ModuleForTests("dex_bootjars", "android_common") + foundLibfooJar := false + base := stem + ".jar" + for _, output := range s.AllOutputs() { + if filepath.Base(output) == base { + foundLibfooJar = true + buildRule := s.Output(output) + android.AssertStringEquals(t, "boot dex jar path", bootDexJarPath, buildRule.Input.String()) + } + } + if !foundLibfooJar { + t.Errorf("Rule for libfoo.jar missing in dex_bootjars singleton outputs %q", android.StringPathsRelativeToTop(ctx.Config().SoongOutDir(), s.AllOutputs())) + } + } + + // Check that the boot jars of the selected apex are run through boot_jars_package_check + // This validates that the jars on the bootclasspath do not contain packages outside an allowlist + checkBootJarsPackageCheck := func(t *testing.T, ctx *android.TestContext, expectedBootJar string) { + platformBcp := ctx.ModuleForTests("platform-bootclasspath", "android_common") + bootJarsCheckRule := platformBcp.Rule("boot_jars_package_check") + android.AssertStringMatches(t, "Could not find the correct boot dex jar in package check rule", bootJarsCheckRule.RuleParams.Command, "build/soong/scripts/check_boot_jars/package_allowed_list.txt.*"+expectedBootJar) + } + + // Check that the boot jars used to generate the monolithic hiddenapi flags come from the selected apex + checkBootJarsForMonolithicHiddenapi := func(t *testing.T, ctx *android.TestContext, expectedBootJar string) { + monolithicHiddenapiFlagsCmd := ctx.ModuleForTests("platform-bootclasspath", "android_common").Output("out/soong/hiddenapi/hiddenapi-stub-flags.txt").RuleParams.Command + android.AssertStringMatches(t, "Could not find the correct boot dex jar in monolithic hiddenapi flags generation command", monolithicHiddenapiFlagsCmd, "--boot-dex="+expectedBootJar) + } + + bp := ` + // Source APEX. + + java_library { + name: "framework-foo", + srcs: ["foo.java"], + installable: true, + apex_available: [ + "com.android.foo", + ], + } + + bootclasspath_fragment { + name: "foo-bootclasspath-fragment", + contents: ["framework-foo"], + apex_available: [ + "com.android.foo", + ], + hidden_api: { + split_packages: ["*"], + }, + } + + apex_key { + name: "com.android.foo.key", + public_key: "com.android.foo.avbpubkey", + private_key: "com.android.foo.pem", + } + + apex { + name: "com.android.foo", + key: "com.android.foo.key", + bootclasspath_fragments: ["foo-bootclasspath-fragment"], + updatable: false, + } + + // Prebuilt APEX. + + java_sdk_library_import { + name: "framework-foo", + public: { + jars: ["foo.jar"], + }, + apex_available: ["com.android.foo"], + shared_library: false, + } + + prebuilt_bootclasspath_fragment { + name: "foo-bootclasspath-fragment", + contents: ["framework-foo"], + hidden_api: { + annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv", + metadata: "my-bootclasspath-fragment/metadata.csv", + index: "my-bootclasspath-fragment/index.csv", + stub_flags: "my-bootclasspath-fragment/stub-flags.csv", + all_flags: "my-bootclasspath-fragment/all-flags.csv", + }, + apex_available: [ + "com.android.foo", + ], + } + + prebuilt_apex { + name: "com.android.foo", + apex_name: "com.android.foo", + src: "com.android.foo-arm.apex", + exported_bootclasspath_fragments: ["foo-bootclasspath-fragment"], + } + + // Another Prebuilt ART APEX + prebuilt_apex { + name: "com.android.foo.v2", + apex_name: "com.android.foo", // Used to determine the API domain + src: "com.android.foo-arm.apex", + exported_bootclasspath_fragments: ["foo-bootclasspath-fragment"], + } + + // APEX contribution modules + + apex_contributions { + name: "foo.source.contributions", + api_domain: "com.android.foo", + contents: ["com.android.foo"], + } + + apex_contributions { + name: "foo.prebuilt.contributions", + api_domain: "com.android.foo", + contents: ["prebuilt_com.android.foo"], + } + + apex_contributions { + name: "foo.prebuilt.v2.contributions", + api_domain: "com.android.foo", + contents: ["com.android.foo.v2"], // prebuilt_ prefix is missing because of prebuilt_rename mutator + } + ` + + testCases := []struct { + desc string + selectedApexContributions string + expectedBootJar string + }{ + { + desc: "Source apex com.android.foo is selected, bootjar should come from source java library", + selectedApexContributions: "foo.source.contributions", + expectedBootJar: "out/soong/.intermediates/foo-bootclasspath-fragment/android_common_apex10000/hiddenapi-modular/encoded/framework-foo.jar", + }, + { + desc: "Prebuilt apex prebuilt_com.android.foo is selected, profile should come from .prof deapexed from the prebuilt", + selectedApexContributions: "foo.prebuilt.contributions", + expectedBootJar: "out/soong/.intermediates/prebuilt_com.android.foo.deapexer/android_common/deapexer/javalib/framework-foo.jar", + }, + { + desc: "Prebuilt apex prebuilt_com.android.foo.v2 is selected, profile should come from .prof deapexed from the prebuilt", + selectedApexContributions: "foo.prebuilt.v2.contributions", + expectedBootJar: "out/soong/.intermediates/prebuilt_com.android.foo.v2.deapexer/android_common/deapexer/javalib/framework-foo.jar", + }, + } + + fragment := java.ApexVariantReference{ + Apex: proptools.StringPtr("com.android.foo"), + Module: proptools.StringPtr("foo-bootclasspath-fragment"), + } + + for _, tc := range testCases { + preparer := android.GroupFixturePreparers( + java.FixtureConfigureApexBootJars("com.android.foo:framework-foo"), + android.FixtureMergeMockFs(map[string][]byte{ + "system/sepolicy/apex/com.android.foo-file_contexts": nil, + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BuildFlags = map[string]string{ + "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": tc.selectedApexContributions, + } + }), + ) + ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment) + checkBootDexJarPath(t, ctx, "framework-foo", tc.expectedBootJar) + checkBootJarsPackageCheck(t, ctx, tc.expectedBootJar) + checkBootJarsForMonolithicHiddenapi(t, ctx, tc.expectedBootJar) + } +} + +// Test that product packaging installs the selected mainline module (either source or a specific prebuilt) +// RELEASE_APEX_CONTIRBUTIONS_* build flags will be used to select the correct prebuilt for a specific release config +func TestInstallationRulesForMultipleApexPrebuilts(t *testing.T) { + // check that the LOCAL_MODULE in the generated mk file matches the name used in PRODUCT_PACKAGES + // Since the name used in PRODUCT_PACKAGES does not contain prebuilt_ prefix, LOCAL_MODULE should not contain any prefix either + checkLocalModuleName := func(t *testing.T, ctx *android.TestContext, soongApexModuleName string, expectedLocalModuleName string) { + // Variations are created based on apex_name + entries := android.AndroidMkEntriesForTest(t, ctx, ctx.ModuleForTests(soongApexModuleName, "android_common_com.android.foo").Module()) + android.AssertStringEquals(t, "LOCAL_MODULE of the prebuilt apex must match the name listed in PRODUCT_PACKAGES", expectedLocalModuleName, entries[0].EntryMap["LOCAL_MODULE"][0]) + } + // for a mainline module family, check that only the flagged soong module is visible to make + checkHideFromMake := func(t *testing.T, ctx *android.TestContext, visibleModuleName string, hiddenModuleNames []string) { + variation := func(moduleName string) string { + ret := "android_common_com.android.foo" + if moduleName == "com.google.android.foo" { + ret = "android_common_com.google.android.foo_com.android.foo" + } + return ret + } + + visibleModule := ctx.ModuleForTests(visibleModuleName, variation(visibleModuleName)).Module() + android.AssertBoolEquals(t, "Apex "+visibleModuleName+" selected using apex_contributions should be visible to make", false, visibleModule.IsHideFromMake()) + + for _, hiddenModuleName := range hiddenModuleNames { + hiddenModule := ctx.ModuleForTests(hiddenModuleName, variation(hiddenModuleName)).Module() + android.AssertBoolEquals(t, "Apex "+hiddenModuleName+" not selected using apex_contributions should be hidden from make", true, hiddenModule.IsHideFromMake()) + + } + } + + bp := ` + apex_key { + name: "com.android.foo.key", + public_key: "com.android.foo.avbpubkey", + private_key: "com.android.foo.pem", + } + + // AOSP source apex + apex { + name: "com.android.foo", + key: "com.android.foo.key", + updatable: false, + } + + // Google source apex + override_apex { + name: "com.google.android.foo", + base: "com.android.foo", + key: "com.android.foo.key", + } + + // Prebuilt Google APEX. + + prebuilt_apex { + name: "com.google.android.foo", + apex_name: "com.android.foo", + src: "com.android.foo-arm.apex", + prefer: true, // prefer is set to true on both the prebuilts to induce an error if flagging is not present + } + + // Another Prebuilt Google APEX + prebuilt_apex { + name: "com.google.android.foo.v2", + apex_name: "com.android.foo", + source_apex_name: "com.google.android.foo", // source_apex_name becomes LOCAL_MODULE in the generated mk file + src: "com.android.foo-arm.apex", + prefer: true, // prefer is set to true on both the prebuilts to induce an error if flagging is not present + } + + // APEX contribution modules + + apex_contributions { + name: "foo.source.contributions", + api_domain: "com.android.foo", + contents: ["com.google.android.foo"], + } + + apex_contributions { + name: "foo.prebuilt.contributions", + api_domain: "com.android.foo", + contents: ["prebuilt_com.google.android.foo"], + } + + apex_contributions { + name: "foo.prebuilt.v2.contributions", + api_domain: "com.android.foo", + contents: ["prebuilt_com.google.android.foo.v2"], + } + + // This is an incompatible module because it selects multiple versions of the same mainline module + apex_contributions { + name: "foo.prebuilt.duplicate.contributions", + api_domain: "com.android.foo", + contents: [ + "prebuilt_com.google.android.foo", + "prebuilt_com.google.android.foo.v2", + ], + } + ` + + testCases := []struct { + desc string + selectedApexContributions string + expectedVisibleModuleName string + expectedHiddenModuleNames []string + expectedError string + }{ + { + desc: "Source apex is selected, prebuilts should be hidden from make", + selectedApexContributions: "foo.source.contributions", + expectedVisibleModuleName: "com.google.android.foo", + expectedHiddenModuleNames: []string{"prebuilt_com.google.android.foo", "prebuilt_com.google.android.foo.v2"}, + }, + { + desc: "Prebuilt apex prebuilt_com.android.foo is selected, source and the other prebuilt should be hidden from make", + selectedApexContributions: "foo.prebuilt.contributions", + expectedVisibleModuleName: "prebuilt_com.google.android.foo", + expectedHiddenModuleNames: []string{"com.google.android.foo", "prebuilt_com.google.android.foo.v2"}, + }, + { + desc: "Prebuilt apex prebuilt_com.android.fooi.v2 is selected, source and the other prebuilt should be hidden from make", + selectedApexContributions: "foo.prebuilt.v2.contributions", + expectedVisibleModuleName: "prebuilt_com.google.android.foo.v2", + expectedHiddenModuleNames: []string{"com.google.android.foo", "prebuilt_com.google.android.foo"}, + }, + { + desc: "Multiple versions of a prebuilt apex is selected in the same release config", + selectedApexContributions: "foo.prebuilt.duplicate.contributions", + expectedError: "Found duplicate variations of the same module in apex_contributions: prebuilt_com.google.android.foo and prebuilt_com.google.android.foo.v2", + }, + } + + for _, tc := range testCases { + preparer := android.GroupFixturePreparers( + android.FixtureMergeMockFs(map[string][]byte{ + "system/sepolicy/apex/com.android.foo-file_contexts": nil, + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BuildFlags = map[string]string{ + "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": tc.selectedApexContributions, + } + }), + ) + if tc.expectedError != "" { + preparer = preparer.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(tc.expectedError)) + testApex(t, bp, preparer) + return + } + ctx := testApex(t, bp, preparer) + + // Check that the LOCAL_MODULE of the two prebuilts is com.android.foo + // This ensures that product packaging can pick them for installation if it has been flagged by apex_contributions + checkLocalModuleName(t, ctx, "prebuilt_com.google.android.foo", "com.google.android.foo") + checkLocalModuleName(t, ctx, "prebuilt_com.google.android.foo.v2", "com.google.android.foo") + + // Check that + // 1. The contents of the selected apex_contributions are visible to make + // 2. The rest of the apexes in the mainline module family (source or other prebuilt) is hidden from make + checkHideFromMake(t, ctx, tc.expectedVisibleModuleName, tc.expectedHiddenModuleNames) + } +} |
