diff options
Diffstat (limited to 'apex/apex_test.go')
-rw-r--r-- | apex/apex_test.go | 4394 |
1 files changed, 3451 insertions, 943 deletions
diff --git a/apex/apex_test.go b/apex/apex_test.go index 3442b6d08..7b01b9481 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -15,12 +15,14 @@ package apex import ( - "io/ioutil" + "fmt" "os" "path" + "path/filepath" "reflect" "regexp" "sort" + "strconv" "strings" "testing" @@ -32,11 +34,10 @@ import ( "android/soong/dexpreopt" prebuilt_etc "android/soong/etc" "android/soong/java" + "android/soong/rust" "android/soong/sh" ) -var buildDir string - // names returns name list from white space separated string func names(s string) (ns []string) { for _, n := range strings.Split(s, " ") { @@ -47,96 +48,127 @@ func names(s string) (ns []string) { return } -func testApexError(t *testing.T, pattern, bp string, handlers ...testCustomizer) { +func testApexError(t *testing.T, pattern, bp string, preparers ...android.FixturePreparer) { t.Helper() - ctx, config := testApexContext(t, bp, handlers...) - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - if len(errs) > 0 { - android.FailIfNoMatchingErrors(t, pattern, errs) - return - } - _, errs = ctx.PrepareBuildActions(config) - if len(errs) > 0 { - android.FailIfNoMatchingErrors(t, pattern, errs) - return - } - - t.Fatalf("missing expected error %q (0 errors are returned)", pattern) + android.GroupFixturePreparers( + prepareForApexTest, + android.GroupFixturePreparers(preparers...), + ). + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)). + RunTestWithBp(t, bp) } -func testApex(t *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) { +func testApex(t *testing.T, bp string, preparers ...android.FixturePreparer) *android.TestContext { t.Helper() - ctx, config := testApexContext(t, bp, handlers...) - _, errs := ctx.ParseBlueprintsFiles(".") - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) - return ctx, config -} -type testCustomizer func(fs map[string][]byte, config android.Config) - -func withFiles(files map[string][]byte) testCustomizer { - return func(fs map[string][]byte, config android.Config) { - for k, v := range files { - fs[k] = v - } + optionalBpPreparer := android.NullFixturePreparer + if bp != "" { + optionalBpPreparer = android.FixtureWithRootAndroidBp(bp) } + + result := android.GroupFixturePreparers( + prepareForApexTest, + android.GroupFixturePreparers(preparers...), + optionalBpPreparer, + ).RunTest(t) + + return result.TestContext +} + +func withFiles(files android.MockFS) android.FixturePreparer { + return files.AddToFixture() } -func withTargets(targets map[android.OsType][]android.Target) testCustomizer { - return func(fs map[string][]byte, config android.Config) { +func withTargets(targets map[android.OsType][]android.Target) android.FixturePreparer { + return android.FixtureModifyConfig(func(config android.Config) { for k, v := range targets { config.Targets[k] = v } - } + }) } -func withManifestPackageNameOverrides(specs []string) testCustomizer { - return func(fs map[string][]byte, config android.Config) { - config.TestProductVariables.ManifestPackageNameOverrides = specs - } -} +// withNativeBridgeTargets sets configuration with targets including: +// - X86_64 (primary) +// - X86 (secondary) +// - Arm64 on X86_64 (native bridge) +// - Arm on X86 (native bridge) +var withNativeBridgeEnabled = android.FixtureModifyConfig( + func(config android.Config) { + config.Targets[android.Android] = []android.Target{ + {Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, + NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""}, + {Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, + NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""}, + {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, + NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86_64", NativeBridgeRelativePath: "arm64"}, + {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, + NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86", NativeBridgeRelativePath: "arm"}, + } + }, +) -func withBinder32bit(_ map[string][]byte, config android.Config) { - config.TestProductVariables.Binder32bit = proptools.BoolPtr(true) +func withManifestPackageNameOverrides(specs []string) android.FixturePreparer { + return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.ManifestPackageNameOverrides = specs + }) } -func withUnbundledBuild(_ map[string][]byte, config android.Config) { - config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true) -} +var withBinder32bit = android.FixtureModifyProductVariables( + func(variables android.FixtureProductVariables) { + variables.Binder32bit = proptools.BoolPtr(true) + }, +) -func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) { - android.ClearApexDependency() +var withUnbundledBuild = android.FixtureModifyProductVariables( + func(variables android.FixtureProductVariables) { + variables.Unbundled_build = proptools.BoolPtr(true) + }, +) - bp = bp + ` +// Legacy preparer used for running tests within the apex package. +// +// This includes everything that was needed to run any test in the apex package prior to the +// introduction of the test fixtures. Tests that are being converted to use fixtures directly +// rather than through the testApex...() methods should avoid using this and instead use the +// various preparers directly, using android.GroupFixturePreparers(...) to group them when +// necessary. +// +// deprecated +var prepareForApexTest = android.GroupFixturePreparers( + // General preparers in alphabetical order as test infrastructure will enforce correct + // registration order. + android.PrepareForTestWithAndroidBuildComponents, + bpf.PrepareForTestWithBpf, + cc.PrepareForTestWithCcBuildComponents, + java.PrepareForTestWithJavaDefaultModules, + prebuilt_etc.PrepareForTestWithPrebuiltEtc, + rust.PrepareForTestWithRustDefaultModules, + sh.PrepareForTestWithShBuildComponents, + + PrepareForTestWithApexBuildComponents, + + // Additional apex test specific preparers. + android.FixtureAddTextFile("system/sepolicy/Android.bp", ` filegroup { name: "myapex-file_contexts", srcs: [ - "system/sepolicy/apex/myapex-file_contexts", + "apex/myapex-file_contexts", ], } - ` - - bp = bp + cc.GatherRequiredDepsForTest(android.Android) - - bp = bp + java.GatherRequiredDepsForTest() - - fs := map[string][]byte{ - "a.java": nil, - "PrebuiltAppFoo.apk": nil, - "PrebuiltAppFooPriv.apk": nil, - "build/make/target/product/security": nil, - "apex_manifest.json": nil, - "AndroidManifest.xml": nil, - "system/sepolicy/apex/myapex-file_contexts": nil, - "system/sepolicy/apex/myapex.updatable-file_contexts": nil, - "system/sepolicy/apex/myapex2-file_contexts": nil, - "system/sepolicy/apex/otherapex-file_contexts": nil, - "system/sepolicy/apex/commonapex-file_contexts": nil, - "system/sepolicy/apex/com.android.vndk-file_contexts": nil, + `), + prepareForTestWithMyapex, + android.FixtureMergeMockFs(android.MockFS{ + "a.java": nil, + "PrebuiltAppFoo.apk": nil, + "PrebuiltAppFooPriv.apk": nil, + "apex_manifest.json": nil, + "AndroidManifest.xml": nil, + "system/sepolicy/apex/myapex.updatable-file_contexts": nil, + "system/sepolicy/apex/myapex2-file_contexts": nil, + "system/sepolicy/apex/otherapex-file_contexts": nil, + "system/sepolicy/apex/com.android.vndk-file_contexts": nil, + "system/sepolicy/apex/com.android.vndk.current-file_contexts": nil, "mylib.cpp": nil, - "mylib_common.cpp": nil, "mytest.cpp": nil, "mytest1.cpp": nil, "mytest2.cpp": nil, @@ -167,94 +199,39 @@ func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*andr "build/make/core/proguard.flags": nil, "build/make/core/proguard_basic_keeps.flags": nil, "dummy.txt": nil, + "baz": nil, + "bar/baz": nil, + "testdata/baz": nil, "AppSet.apks": nil, - } - - cc.GatherRequiredFilesForTest(fs) - - for _, handler := range handlers { - // The fs now needs to be populated before creating the config, call handlers twice - // for now, once to get any fs changes, and later after the config was created to - // set product variables or targets. - tempConfig := android.TestArchConfig(buildDir, nil, bp, fs) - handler(fs, tempConfig) - } - - config := android.TestArchConfig(buildDir, nil, bp, fs) - config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current") - config.TestProductVariables.DefaultAppCertificate = proptools.StringPtr("vendor/foo/devkeys/test") - config.TestProductVariables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"} - config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("Q") - config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(false) - config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER") - - for _, handler := range handlers { - // The fs now needs to be populated before creating the config, call handlers twice - // for now, earlier to get any fs changes, and now after the config was created to - // set product variables or targets. - tempFS := map[string][]byte{} - handler(tempFS, config) - } - - ctx := android.NewTestArchContext() - - // from android package - android.RegisterPackageBuildComponents(ctx) - ctx.PreArchMutators(android.RegisterVisibilityRuleChecker) - - ctx.RegisterModuleType("apex", BundleFactory) - ctx.RegisterModuleType("apex_test", testApexBundleFactory) - ctx.RegisterModuleType("apex_vndk", vndkApexBundleFactory) - ctx.RegisterModuleType("apex_key", ApexKeyFactory) - ctx.RegisterModuleType("apex_defaults", defaultsFactory) - ctx.RegisterModuleType("prebuilt_apex", PrebuiltFactory) - ctx.RegisterModuleType("override_apex", overrideApexFactory) - ctx.RegisterModuleType("apex_set", apexSetFactory) - - ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) - ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators) - - cc.RegisterRequiredBuildComponentsForTest(ctx) - - // Register this after the prebuilt mutators have been registered (in - // cc.RegisterRequiredBuildComponentsForTest) to match what happens at runtime. - ctx.PreArchMutators(android.RegisterVisibilityRuleGatherer) - ctx.PostDepsMutators(android.RegisterVisibilityRuleEnforcer) - - ctx.RegisterModuleType("cc_test", cc.TestFactory) - ctx.RegisterModuleType("vndk_prebuilt_shared", cc.VndkPrebuiltSharedFactory) - ctx.RegisterModuleType("vndk_libraries_txt", cc.VndkLibrariesTxtFactory) - ctx.RegisterModuleType("prebuilt_etc", prebuilt_etc.PrebuiltEtcFactory) - ctx.RegisterModuleType("platform_compat_config", java.PlatformCompatConfigFactory) - ctx.RegisterModuleType("sh_binary", sh.ShBinaryFactory) - ctx.RegisterModuleType("filegroup", android.FileGroupFactory) - java.RegisterJavaBuildComponents(ctx) - java.RegisterSystemModulesBuildComponents(ctx) - java.RegisterAppBuildComponents(ctx) - java.RegisterSdkLibraryBuildComponents(ctx) - ctx.RegisterSingletonType("apex_keys_text", apexKeysTextFactory) - ctx.RegisterModuleType("bpf", bpf.BpfFactory) - - ctx.PreDepsMutators(RegisterPreDepsMutators) - ctx.PostDepsMutators(RegisterPostDepsMutators) + "foo.rs": nil, + "libfoo.jar": nil, + "libbar.jar": nil, + }, + ), + + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.DeviceVndkVersion = proptools.StringPtr("current") + variables.DefaultAppCertificate = proptools.StringPtr("vendor/foo/devkeys/test") + variables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"} + variables.Platform_sdk_codename = proptools.StringPtr("Q") + variables.Platform_sdk_final = proptools.BoolPtr(false) + variables.Platform_version_active_codenames = []string{"Q"} + variables.Platform_vndk_version = proptools.StringPtr("29") + }), +) - ctx.Register(config) +var prepareForTestWithMyapex = android.FixtureMergeMockFs(android.MockFS{ + "system/sepolicy/apex/myapex-file_contexts": nil, +}) - return ctx, config -} - -func setUp() { - var err error - buildDir, err = ioutil.TempDir("", "soong_apex_test") - if err != nil { - panic(err) +// ensure that 'result' equals 'expected' +func ensureEquals(t *testing.T, result string, expected string) { + t.Helper() + if result != expected { + t.Errorf("%q != %q", expected, result) } } -func tearDown() { - _ = os.RemoveAll(buildDir) -} - // ensure that 'result' contains 'expected' func ensureContains(t *testing.T, result string, expected string) { t.Helper() @@ -263,6 +240,15 @@ func ensureContains(t *testing.T, result string, expected string) { } } +// ensure that 'result' contains 'expected' exactly one time +func ensureContainsOnce(t *testing.T, result string, expected string) { + t.Helper() + count := strings.Count(result, expected) + if count != 1 { + t.Errorf("%q is found %d times (expected 1 time) in %q", expected, count, result) + } +} + // ensures that 'result' does not contain 'notExpected' func ensureNotContains(t *testing.T, result string, notExpected string) { t.Helper() @@ -303,24 +289,37 @@ func ensureListEmpty(t *testing.T, result []string) { } } +func ensureListNotEmpty(t *testing.T, result []string) { + t.Helper() + if len(result) == 0 { + t.Errorf("%q is expected to be not empty", result) + } +} + // Minimal test func TestBasicApex(t *testing.T) { - ctx, config := testApex(t, ` + ctx := testApex(t, ` apex_defaults { name: "myapex-defaults", manifest: ":myapex.manifest", androidManifest: ":myapex.androidmanifest", key: "myapex.key", - native_shared_libs: ["mylib"], + binaries: ["foo.rust"], + native_shared_libs: [ + "mylib", + "libfoo.ffi", + ], + rust_dyn_libs: ["libfoo.dylib.rust"], multilib: { both: { - binaries: ["foo",], + binaries: ["foo"], } }, java_libs: [ "myjar", "myjar_dex", ], + updatable: false, } apex { @@ -347,7 +346,10 @@ func TestBasicApex(t *testing.T) { cc_library { name: "mylib", srcs: ["mylib.cpp"], - shared_libs: ["mylib2"], + shared_libs: [ + "mylib2", + "libbar.ffi", + ], system_shared_libs: [], stl: "none", // TODO: remove //apex_available:platform @@ -374,7 +376,60 @@ func TestBasicApex(t *testing.T) { system_shared_libs: [], static_executable: true, stl: "none", - apex_available: [ "myapex" ], + apex_available: [ "myapex", "com.android.gki.*" ], + } + + rust_binary { + name: "foo.rust", + srcs: ["foo.rs"], + rlibs: ["libfoo.rlib.rust"], + dylibs: ["libfoo.dylib.rust"], + apex_available: ["myapex"], + } + + rust_library_rlib { + name: "libfoo.rlib.rust", + srcs: ["foo.rs"], + crate_name: "foo", + apex_available: ["myapex"], + shared_libs: ["libfoo.shared_from_rust"], + } + + cc_library_shared { + name: "libfoo.shared_from_rust", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: ["myapex"], + } + + rust_library_dylib { + name: "libfoo.dylib.rust", + srcs: ["foo.rs"], + crate_name: "foo", + apex_available: ["myapex"], + } + + rust_ffi_shared { + name: "libfoo.ffi", + srcs: ["foo.rs"], + crate_name: "foo", + apex_available: ["myapex"], + } + + rust_ffi_shared { + name: "libbar.ffi", + srcs: ["foo.rs"], + crate_name: "bar", + apex_available: ["myapex"], + } + + apex { + name: "com.android.gki.fake", + binaries: ["foo"], + key: "myapex.key", + file_contexts: ":myapex-file_contexts", + updatable: false, } cc_library_shared { @@ -462,7 +517,7 @@ func TestBasicApex(t *testing.T) { // Make sure that Android.mk is created ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) - data := android.AndroidMkDataForTest(t, config, "", ab) + data := android.AndroidMkDataForTest(t, ctx, ab) var builder strings.Builder data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data) @@ -473,7 +528,7 @@ func TestBasicApex(t *testing.T) { optFlags := apexRule.Args["opt_flags"] ensureContains(t, optFlags, "--pubkey vendor/foo/devkeys/testkey.avbpubkey") // Ensure that the NOTICE output is being packaged as an asset. - ensureContains(t, optFlags, "--assets_dir "+buildDir+"/.intermediates/myapex/android_common_myapex_image/NOTICE") + ensureContains(t, optFlags, "--assets_dir out/soong/.intermediates/myapex/android_common_myapex_image/NOTICE") copyCmds := apexRule.Args["copy_commands"] @@ -481,19 +536,29 @@ func TestBasicApex(t *testing.T) { ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned") // Ensure that apex variant is created for the direct dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex") - ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_myapex") - ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("foo.rust"), "android_arm64_armv8-a_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.ffi"), "android_arm64_armv8-a_shared_apex10000") // Ensure that apex variant is created for the indirect dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex") - ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.rlib.rust"), "android_arm64_armv8-a_rlib_dylib-std_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.dylib.rust"), "android_arm64_armv8-a_dylib_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("libbar.ffi"), "android_arm64_armv8-a_shared_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.shared_from_rust"), "android_arm64_armv8-a_shared_apex10000") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") ensureContains(t, copyCmds, "image.apex/lib64/mylib2.so") ensureContains(t, copyCmds, "image.apex/javalib/myjar_stem.jar") ensureContains(t, copyCmds, "image.apex/javalib/myjar_dex.jar") + ensureContains(t, copyCmds, "image.apex/lib64/libfoo.dylib.rust.dylib.so") + ensureContains(t, copyCmds, "image.apex/lib64/libfoo.ffi.so") + ensureContains(t, copyCmds, "image.apex/lib64/libbar.ffi.so") + ensureContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so") // .. but not for java libs ensureNotContains(t, copyCmds, "image.apex/javalib/myotherjar.jar") ensureNotContains(t, copyCmds, "image.apex/javalib/msharedjar.jar") @@ -548,7 +613,7 @@ func TestBasicApex(t *testing.T) { } func TestDefaults(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex_defaults { name: "myapex-defaults", key: "myapex.key", @@ -556,7 +621,9 @@ func TestDefaults(t *testing.T) { native_shared_libs: ["mylib"], java_libs: ["myjar"], apps: ["AppFoo"], + rros: ["rro"], bpfs: ["bpf"], + updatable: false, } prebuilt_etc { @@ -598,6 +665,11 @@ func TestDefaults(t *testing.T) { apex_available: [ "myapex" ], } + runtime_resource_overlay { + name: "rro", + theme: "blue", + } + bpf { name: "bpf", srcs: ["bpf.c", "bpf2.c"], @@ -609,16 +681,18 @@ func TestDefaults(t *testing.T) { "javalib/myjar.jar", "lib64/mylib.so", "app/AppFoo/AppFoo.apk", + "overlay/blue/rro.apk", "etc/bpf/bpf.o", "etc/bpf/bpf2.o", }) } func TestApexManifest(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", + updatable: false, } apex_key { @@ -636,12 +710,13 @@ func TestApexManifest(t *testing.T) { } func TestBasicZipApex(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", payload_type: "zip", native_shared_libs: ["mylib"], + updatable: false, } apex_key { @@ -675,10 +750,10 @@ func TestBasicZipApex(t *testing.T) { ensureContains(t, zipApexRule.Output.String(), "myapex.zipapex.unsigned") // Ensure that APEX variant is created for the direct dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000") // Ensure that APEX variant is created for the indirect dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.zipapex/lib64/mylib.so") @@ -686,11 +761,12 @@ func TestBasicZipApex(t *testing.T) { } func TestApexWithStubs(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib", "mylib3"], + updatable: false, } apex_key { @@ -752,24 +828,123 @@ func TestApexWithStubs(t *testing.T) { // Ensure that direct stubs dep is included ensureContains(t, copyCmds, "image.apex/lib64/mylib3.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"] + mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] // Ensure that mylib is linking with the latest version of stubs for mylib2 - ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_3/mylib2.so") + ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so") // ... and not linking to the non-stub (impl) variant of mylib2 ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so") // Ensure that mylib is linking with the non-stub (impl) of mylib3 (because mylib3 is in the same apex) - ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_myapex/mylib3.so") + ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_apex10000/mylib3.so") // .. and not linking to the stubs variant of mylib3 - ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12_myapex/mylib3.so") + ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12/mylib3.so") // Ensure that stubs libs are built without -include flags mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] ensureNotContains(t, mylib2Cflags, "-include ") // Ensure that genstub is invoked with --apex - ensureContains(t, "--apex", ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_3").Rule("genStubSrc").Args["flags"]) + ensureContains(t, "--apex", ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"]) + + ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + "lib64/mylib.so", + "lib64/mylib3.so", + "lib64/mylib4.so", + }) +} + +func TestApexWithStubsWithMinSdkVersion(t *testing.T) { + t.Parallel() + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib", "mylib3"], + min_sdk_version: "29", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + shared_libs: ["mylib2", "mylib3"], + system_shared_libs: [], + stl: "none", + apex_available: [ "myapex" ], + min_sdk_version: "28", + } + + cc_library { + name: "mylib2", + srcs: ["mylib.cpp"], + cflags: ["-include mylib.h"], + system_shared_libs: [], + stl: "none", + stubs: { + versions: ["28", "29", "30", "current"], + }, + min_sdk_version: "28", + } + + cc_library { + name: "mylib3", + srcs: ["mylib.cpp"], + shared_libs: ["mylib4"], + system_shared_libs: [], + stl: "none", + stubs: { + versions: ["28", "29", "30", "current"], + }, + apex_available: [ "myapex" ], + min_sdk_version: "28", + } + + cc_library { + name: "mylib4", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: [ "myapex" ], + min_sdk_version: "28", + } + `) + + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + copyCmds := apexRule.Args["copy_commands"] + + // Ensure that direct non-stubs dep is always included + ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") + + // Ensure that indirect stubs dep is not included + ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so") + + // Ensure that direct stubs dep is included + ensureContains(t, copyCmds, "image.apex/lib64/mylib3.so") + + mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex29").Rule("ld").Args["libFlags"] + + // Ensure that mylib is linking with the latest version of stub for mylib2 + ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so") + // ... and not linking to the non-stub (impl) variant of mylib2 + ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so") + + // Ensure that mylib is linking with the non-stub (impl) of mylib3 (because mylib3 is in the same apex) + ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_apex29/mylib3.so") + // .. and not linking to the stubs variant of mylib3 + ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_29/mylib3.so") + + // Ensure that stubs libs are built without -include flags + mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("cc").Args["cFlags"] + ensureNotContains(t, mylib2Cflags, "-include ") + + // Ensure that genstub is invoked with --apex + ensureContains(t, "--apex", ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("genStubSrc").Args["flags"]) ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ "lib64/mylib.so", @@ -778,12 +953,89 @@ func TestApexWithStubs(t *testing.T) { }) } +func TestApex_PlatformUsesLatestStubFromApex(t *testing.T) { + t.Parallel() + // myapex (Z) + // mylib -----------------. + // | + // otherapex (29) | + // libstub's versions: 29 Z current + // | + // <platform> | + // libplatform ----------------' + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib"], + min_sdk_version: "Z", // non-final + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + shared_libs: ["libstub"], + apex_available: ["myapex"], + min_sdk_version: "Z", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + apex { + name: "otherapex", + key: "myapex.key", + native_shared_libs: ["libstub"], + min_sdk_version: "29", + } + + cc_library { + name: "libstub", + srcs: ["mylib.cpp"], + stubs: { + versions: ["29", "Z", "current"], + }, + apex_available: ["otherapex"], + min_sdk_version: "29", + } + + // platform module depending on libstub from otherapex should use the latest stub("current") + cc_library { + name: "libplatform", + srcs: ["mylib.cpp"], + shared_libs: ["libstub"], + } + `, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.Platform_sdk_codename = proptools.StringPtr("Z") + variables.Platform_sdk_final = proptools.BoolPtr(false) + variables.Platform_version_active_codenames = []string{"Z"} + }), + ) + + // Ensure that mylib from myapex is built against the latest stub (current) + mylibCflags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"] + ensureContains(t, mylibCflags, "-D__LIBSTUB_API__=10000 ") + mylibLdflags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] + ensureContains(t, mylibLdflags, "libstub/android_arm64_armv8-a_shared_current/libstub.so ") + + // Ensure that libplatform is built against latest stub ("current") of mylib3 from the apex + libplatformCflags := ctx.ModuleForTests("libplatform", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + ensureContains(t, libplatformCflags, "-D__LIBSTUB_API__=10000 ") // "current" maps to 10000 + libplatformLdflags := ctx.ModuleForTests("libplatform", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"] + ensureContains(t, libplatformLdflags, "libstub/android_arm64_armv8-a_shared_current/libstub.so ") +} + func TestApexWithExplicitStubsDependency(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex2", key: "myapex2.key", native_shared_libs: ["mylib"], + updatable: false, } apex_key { @@ -842,7 +1094,7 @@ func TestApexWithExplicitStubsDependency(t *testing.T) { // Ensure that dependency of stubs is not included ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex2").Rule("ld").Args["libFlags"] + mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] // Ensure that mylib is linking with version 10 of libfoo ensureContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared_10/libfoo.so") @@ -870,11 +1122,12 @@ func TestApexWithRuntimeLibsDependency(t *testing.T) { | `------> libbar */ - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], + updatable: false, } apex_key { @@ -930,35 +1183,152 @@ func TestApexWithRuntimeLibsDependency(t *testing.T) { } +var prepareForTestOfRuntimeApexWithHwasan = android.GroupFixturePreparers( + cc.PrepareForTestWithCcBuildComponents, + PrepareForTestWithApexBuildComponents, + android.FixtureAddTextFile("bionic/apex/Android.bp", ` + apex { + name: "com.android.runtime", + key: "com.android.runtime.key", + native_shared_libs: ["libc"], + updatable: false, + } + + apex_key { + name: "com.android.runtime.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + `), + android.FixtureAddFile("system/sepolicy/apex/com.android.runtime-file_contexts", nil), +) + +func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) { + result := android.GroupFixturePreparers(prepareForTestOfRuntimeApexWithHwasan).RunTestWithBp(t, ` + cc_library { + name: "libc", + no_libcrt: true, + nocrt: true, + stl: "none", + system_shared_libs: [], + stubs: { versions: ["1"] }, + apex_available: ["com.android.runtime"], + + sanitize: { + hwaddress: true, + } + } + + cc_prebuilt_library_shared { + name: "libclang_rt.hwasan-aarch64-android", + no_libcrt: true, + nocrt: true, + stl: "none", + system_shared_libs: [], + srcs: [""], + stubs: { versions: ["1"] }, + + sanitize: { + never: true, + }, + } `) + ctx := result.TestContext + + ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime_image", []string{ + "lib64/bionic/libc.so", + "lib64/bionic/libclang_rt.hwasan-aarch64-android.so", + }) + + hwasan := ctx.ModuleForTests("libclang_rt.hwasan-aarch64-android", "android_arm64_armv8-a_shared") + + installed := hwasan.Description("install libclang_rt.hwasan") + ensureContains(t, installed.Output.String(), "/system/lib64/bootstrap/libclang_rt.hwasan-aarch64-android.so") + + symlink := hwasan.Description("install symlink libclang_rt.hwasan") + ensureEquals(t, symlink.Args["fromPath"], "/apex/com.android.runtime/lib64/bionic/libclang_rt.hwasan-aarch64-android.so") + ensureContains(t, symlink.Output.String(), "/system/lib64/libclang_rt.hwasan-aarch64-android.so") +} + +func TestRuntimeApexShouldInstallHwasanIfHwaddressSanitized(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForTestOfRuntimeApexWithHwasan, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.SanitizeDevice = []string{"hwaddress"} + }), + ).RunTestWithBp(t, ` + cc_library { + name: "libc", + no_libcrt: true, + nocrt: true, + stl: "none", + system_shared_libs: [], + stubs: { versions: ["1"] }, + apex_available: ["com.android.runtime"], + } + + cc_prebuilt_library_shared { + name: "libclang_rt.hwasan-aarch64-android", + no_libcrt: true, + nocrt: true, + stl: "none", + system_shared_libs: [], + srcs: [""], + stubs: { versions: ["1"] }, + + sanitize: { + never: true, + }, + } + `) + ctx := result.TestContext + + ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime_image", []string{ + "lib64/bionic/libc.so", + "lib64/bionic/libclang_rt.hwasan-aarch64-android.so", + }) + + hwasan := ctx.ModuleForTests("libclang_rt.hwasan-aarch64-android", "android_arm64_armv8-a_shared") + + installed := hwasan.Description("install libclang_rt.hwasan") + ensureContains(t, installed.Output.String(), "/system/lib64/bootstrap/libclang_rt.hwasan-aarch64-android.so") + + symlink := hwasan.Description("install symlink libclang_rt.hwasan") + ensureEquals(t, symlink.Args["fromPath"], "/apex/com.android.runtime/lib64/bionic/libclang_rt.hwasan-aarch64-android.so") + ensureContains(t, symlink.Output.String(), "/system/lib64/libclang_rt.hwasan-aarch64-android.so") +} + func TestApexDependsOnLLNDKTransitively(t *testing.T) { testcases := []struct { name string minSdkVersion string + apexVariant string shouldLink string shouldNotLink []string }{ { - name: "should link to the latest", - minSdkVersion: "current", - shouldLink: "30", - shouldNotLink: []string{"29"}, + name: "unspecified version links to the latest", + minSdkVersion: "", + apexVariant: "apex10000", + shouldLink: "current", + shouldNotLink: []string{"29", "30"}, }, { - name: "should link to llndk#29", - minSdkVersion: "29", - shouldLink: "29", - shouldNotLink: []string{"30"}, + name: "always use the latest", + minSdkVersion: "min_sdk_version: \"29\",", + apexVariant: "apex29", + shouldLink: "current", + shouldNotLink: []string{"29", "30"}, }, } for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", - use_vendor: true, native_shared_libs: ["mylib"], - min_sdk_version: "`+tc.minSdkVersion+`", + updatable: false, + `+tc.minSdkVersion+` } apex_key { @@ -975,6 +1345,7 @@ func TestApexDependsOnLLNDKTransitively(t *testing.T) { system_shared_libs: [], stl: "none", apex_available: [ "myapex" ], + min_sdk_version: "29", } cc_library { @@ -983,15 +1354,13 @@ func TestApexDependsOnLLNDKTransitively(t *testing.T) { system_shared_libs: [], stl: "none", stubs: { versions: ["29","30"] }, + llndk: { + symbol_file: "libbar.map.txt", + } } - - llndk_library { - name: "libbar", - symbol_file: "", - } - `, func(fs map[string][]byte, config android.Config) { - setUseVendorAllowListForTest(config, []string{"myapex"}) - }, withUnbundledBuild) + `, + withUnbundledBuild, + ) // Ensure that LLNDK dep is not included ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ @@ -1003,24 +1372,29 @@ func TestApexDependsOnLLNDKTransitively(t *testing.T) { ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"])) ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"] - ensureContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+tc.shouldLink+"/libbar.so") + mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_"+tc.apexVariant).Rule("ld").Args["libFlags"] + ensureContains(t, mylibLdFlags, "libbar/android_arm64_armv8-a_shared_"+tc.shouldLink+"/libbar.so") for _, ver := range tc.shouldNotLink { - ensureNotContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+ver+"/libbar.so") + ensureNotContains(t, mylibLdFlags, "libbar/android_arm64_armv8-a_shared_"+ver+"/libbar.so") } - mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] - ensureContains(t, mylibCFlags, "__LIBBAR_API__="+tc.shouldLink) + mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_"+tc.apexVariant).Rule("cc").Args["cFlags"] + ver := tc.shouldLink + if tc.shouldLink == "current" { + ver = strconv.Itoa(android.FutureApiLevelInt) + } + ensureContains(t, mylibCFlags, "__LIBBAR_API__="+ver) }) } } func TestApexWithSystemLibsStubs(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib", "mylib_shared", "libdl", "libm"], + updatable: false, } apex_key { @@ -1032,6 +1406,7 @@ func TestApexWithSystemLibsStubs(t *testing.T) { cc_library { name: "mylib", srcs: ["mylib.cpp"], + system_shared_libs: ["libc", "libm"], shared_libs: ["libdl#27"], stl: "none", apex_available: [ "myapex" ], @@ -1064,22 +1439,22 @@ func TestApexWithSystemLibsStubs(t *testing.T) { // Ensure that libc is not included (since it has stubs and not listed in native_shared_libs) ensureNotContains(t, copyCmds, "image.apex/lib64/bionic/libc.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"] - mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] - mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_shared_myapex").Rule("cc").Args["cFlags"] + mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] + mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"] + mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_shared_apex10000").Rule("cc").Args["cFlags"] // For dependency to libc // Ensure that mylib is linking with the latest version of stubs - ensureContains(t, mylibLdFlags, "libc/android_arm64_armv8-a_shared_29/libc.so") + ensureContains(t, mylibLdFlags, "libc/android_arm64_armv8-a_shared_current/libc.so") // ... and not linking to the non-stub (impl) variant ensureNotContains(t, mylibLdFlags, "libc/android_arm64_armv8-a_shared/libc.so") // ... Cflags from stub is correctly exported to mylib - ensureContains(t, mylibCFlags, "__LIBC_API__=29") - ensureContains(t, mylibSharedCFlags, "__LIBC_API__=29") + ensureContains(t, mylibCFlags, "__LIBC_API__=10000") + ensureContains(t, mylibSharedCFlags, "__LIBC_API__=10000") // For dependency to libm // Ensure that mylib is linking with the non-stub (impl) variant - ensureContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_myapex/libm.so") + ensureContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_apex10000/libm.so") // ... and not linking to the stub variant ensureNotContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_29/libm.so") // ... and is not compiling with the stub @@ -1093,7 +1468,7 @@ func TestApexWithSystemLibsStubs(t *testing.T) { ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_28/libdl.so") ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_29/libdl.so") // ... and not linking to the non-stub (impl) variant - ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_myapex/libdl.so") + ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_apex10000/libdl.so") // ... Cflags from stub is correctly exported to mylib ensureContains(t, mylibCFlags, "__LIBDL_API__=27") ensureContains(t, mylibSharedCFlags, "__LIBDL_API__=27") @@ -1105,24 +1480,24 @@ func TestApexWithSystemLibsStubs(t *testing.T) { ensureContains(t, libFlags, "libdl/android_arm64_armv8-a_shared/libdl.so") } -func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) { - // there are three links between liba --> libz - // 1) myapex -> libx -> liba -> libz : this should be #2 link, but fallback to #1 - // 2) otherapex -> liby -> liba -> libz : this should be #3 link +func TestApexMinSdkVersion_NativeModulesShouldBeBuiltAgainstStubs(t *testing.T) { + // there are three links between liba --> libz. + // 1) myapex -> libx -> liba -> libz : this should be #30 link + // 2) otherapex -> liby -> liba -> libz : this should be #30 link // 3) (platform) -> liba -> libz : this should be non-stub link - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["libx"], - min_sdk_version: "2", + min_sdk_version: "29", } apex { name: "otherapex", key: "myapex.key", native_shared_libs: ["liby"], - min_sdk_version: "3", + min_sdk_version: "30", } apex_key { @@ -1137,6 +1512,7 @@ func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) { system_shared_libs: [], stl: "none", apex_available: [ "myapex" ], + min_sdk_version: "29", } cc_library { @@ -1145,6 +1521,7 @@ func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) { system_shared_libs: [], stl: "none", apex_available: [ "otherapex" ], + min_sdk_version: "29", } cc_library { @@ -1156,6 +1533,7 @@ func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) { "//apex_available:anyapex", "//apex_available:platform", ], + min_sdk_version: "29", } cc_library { @@ -1163,10 +1541,10 @@ func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) { system_shared_libs: [], stl: "none", stubs: { - versions: ["1", "3"], + versions: ["28", "30"], }, } - `, withUnbundledBuild) + `) expectLink := func(from, from_variant, to, to_variant string) { ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] @@ -1178,18 +1556,20 @@ func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) { } // platform liba is linked to non-stub version expectLink("liba", "shared", "libz", "shared") - // liba in myapex is linked to #1 - expectLink("liba", "shared_myapex", "libz", "shared_1") - expectNoLink("liba", "shared_myapex", "libz", "shared_3") - expectNoLink("liba", "shared_myapex", "libz", "shared") - // liba in otherapex is linked to #3 - expectLink("liba", "shared_otherapex", "libz", "shared_3") - expectNoLink("liba", "shared_otherapex", "libz", "shared_1") - expectNoLink("liba", "shared_otherapex", "libz", "shared") + // liba in myapex is linked to current + expectLink("liba", "shared_apex29", "libz", "shared_current") + expectNoLink("liba", "shared_apex29", "libz", "shared_30") + expectNoLink("liba", "shared_apex29", "libz", "shared_28") + expectNoLink("liba", "shared_apex29", "libz", "shared") + // liba in otherapex is linked to current + expectLink("liba", "shared_apex30", "libz", "shared_current") + expectNoLink("liba", "shared_apex30", "libz", "shared_30") + expectNoLink("liba", "shared_apex30", "libz", "shared_28") + expectNoLink("liba", "shared_apex30", "libz", "shared") } func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", @@ -1209,6 +1589,7 @@ func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) { system_shared_libs: [], stl: "none", apex_available: [ "myapex" ], + min_sdk_version: "R", } cc_library { @@ -1219,9 +1600,11 @@ func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) { versions: ["29", "R"], }, } - `, func(fs map[string][]byte, config android.Config) { - config.TestProductVariables.Platform_version_active_codenames = []string{"R"} - }) + `, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.Platform_version_active_codenames = []string{"R"} + }), + ) expectLink := func(from, from_variant, to, to_variant string) { ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] @@ -1231,23 +1614,19 @@ func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) { ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } - // 9000 is quite a magic number. - // Finalized SDK codenames are mapped as P(28), Q(29), ... - // And, codenames which are not finalized yet(active_codenames + future_codenames) are numbered from 9000, 9001, ... - // to distinguish them from finalized and future_api(10000) - // In this test, "R" is assumed not finalized yet( listed in Platform_version_active_codenames) and translated into 9000 - // (refer android/api_levels.go) - expectLink("libx", "shared_myapex", "libz", "shared_9000") - expectNoLink("libx", "shared_myapex", "libz", "shared_29") - expectNoLink("libx", "shared_myapex", "libz", "shared") -} - -func TestApexMinSdkVersionDefaultsToLatest(t *testing.T) { - ctx, _ := testApex(t, ` + expectLink("libx", "shared_apex10000", "libz", "shared_current") + expectNoLink("libx", "shared_apex10000", "libz", "shared_R") + expectNoLink("libx", "shared_apex10000", "libz", "shared_29") + expectNoLink("libx", "shared_apex10000", "libz", "shared") +} + +func TestApexMinSdkVersion_DefaultsToLatest(t *testing.T) { + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["libx"], + updatable: false, } apex_key { @@ -1282,17 +1661,19 @@ func TestApexMinSdkVersionDefaultsToLatest(t *testing.T) { ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } - expectLink("libx", "shared_myapex", "libz", "shared_2") - expectNoLink("libx", "shared_myapex", "libz", "shared_1") - expectNoLink("libx", "shared_myapex", "libz", "shared") + expectLink("libx", "shared_apex10000", "libz", "shared_current") + expectNoLink("libx", "shared_apex10000", "libz", "shared_1") + expectNoLink("libx", "shared_apex10000", "libz", "shared_2") + expectNoLink("libx", "shared_apex10000", "libz", "shared") } func TestPlatformUsesLatestStubsFromApexes(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["libx"], + updatable: false, } apex_key { @@ -1320,20 +1701,29 @@ func TestPlatformUsesLatestStubsFromApexes(t *testing.T) { `) expectLink := func(from, from_variant, to, to_variant string) { + t.Helper() ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } expectNoLink := func(from, from_variant, to, to_variant string) { + t.Helper() ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } - expectLink("libz", "shared", "libx", "shared_2") + expectLink("libz", "shared", "libx", "shared_current") + expectNoLink("libz", "shared", "libx", "shared_2") expectNoLink("libz", "shared", "libz", "shared_1") expectNoLink("libz", "shared", "libz", "shared") } +var prepareForTestWithSantitizeHwaddress = android.FixtureModifyProductVariables( + func(variables android.FixtureProductVariables) { + variables.SanitizeDevice = []string{"hwaddress"} + }, +) + func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", @@ -1351,6 +1741,7 @@ func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) { name: "libx", shared_libs: ["libbar"], apex_available: [ "myapex" ], + min_sdk_version: "29", } cc_library { @@ -1359,19 +1750,19 @@ func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) { versions: ["29", "30"], }, } - `, func(fs map[string][]byte, config android.Config) { - config.TestProductVariables.SanitizeDevice = []string{"hwaddress"} - }) + `, + prepareForTestWithSantitizeHwaddress, + ) expectLink := func(from, from_variant, to, to_variant string) { ld := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld") libFlags := ld.Args["libFlags"] ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } - expectLink("libx", "shared_hwasan_myapex", "libbar", "shared_30") + expectLink("libx", "shared_hwasan_apex29", "libbar", "shared_current") } func TestQTargetApexUsesStaticUnwinder(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", @@ -1388,23 +1779,24 @@ func TestQTargetApexUsesStaticUnwinder(t *testing.T) { cc_library { name: "libx", apex_available: [ "myapex" ], + min_sdk_version: "29", } `) // ensure apex variant of c++ is linked with static unwinder - cm := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module) - ensureListContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped") + cm := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared_apex29").Module().(*cc.Module) + ensureListContains(t, cm.Properties.AndroidMkStaticLibs, "libunwind") // note that platform variant is not. cm = ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared").Module().(*cc.Module) - ensureListNotContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped") + ensureListNotContains(t, cm.Properties.AndroidMkStaticLibs, "libunwind") } -func TestInvalidMinSdkVersion(t *testing.T) { - testApexError(t, `"libz" .*: not found a version\(<=29\)`, ` +func TestApexMinSdkVersion_ErrorIfIncompatibleVersion(t *testing.T) { + testApexError(t, `module "mylib".*: should support min_sdk_version\(29\)`, ` apex { name: "myapex", key: "myapex.key", - native_shared_libs: ["libx"], + native_shared_libs: ["mylib"], min_sdk_version: "29", } @@ -1415,28 +1807,75 @@ func TestInvalidMinSdkVersion(t *testing.T) { } cc_library { - name: "libx", - shared_libs: ["libz"], + name: "mylib", + srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", - apex_available: [ "myapex" ], + apex_available: [ + "myapex", + ], + min_sdk_version: "30", } + `) - cc_library { - name: "libz", - system_shared_libs: [], - stl: "none", - stubs: { - versions: ["30"], - }, + testApexError(t, `module "libfoo.ffi".*: should support min_sdk_version\(29\)`, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["libfoo.ffi"], + min_sdk_version: "29", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + rust_ffi_shared { + name: "libfoo.ffi", + srcs: ["foo.rs"], + crate_name: "foo", + apex_available: [ + "myapex", + ], + min_sdk_version: "30", + } + `) + + testApexError(t, `module "libfoo".*: should support min_sdk_version\(29\)`, ` + apex { + name: "myapex", + key: "myapex.key", + java_libs: ["libfoo"], + min_sdk_version: "29", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + java_import { + name: "libfoo", + jars: ["libfoo.jar"], + apex_available: [ + "myapex", + ], + min_sdk_version: "30", } `) +} - testApexError(t, `"myapex" .*: min_sdk_version: SDK version should be .*`, ` +func TestApexMinSdkVersion_Okay(t *testing.T) { + testApex(t, ` apex { name: "myapex", key: "myapex.key", - min_sdk_version: "abc", + native_shared_libs: ["libfoo"], + java_libs: ["libbar"], + min_sdk_version: "29", } apex_key { @@ -1444,6 +1883,48 @@ func TestInvalidMinSdkVersion(t *testing.T) { public_key: "testkey.avbpubkey", private_key: "testkey.pem", } + + cc_library { + name: "libfoo", + srcs: ["mylib.cpp"], + shared_libs: ["libfoo_dep"], + apex_available: ["myapex"], + min_sdk_version: "29", + } + + cc_library { + name: "libfoo_dep", + srcs: ["mylib.cpp"], + apex_available: ["myapex"], + min_sdk_version: "29", + } + + java_library { + name: "libbar", + sdk_version: "current", + srcs: ["a.java"], + static_libs: [ + "libbar_dep", + "libbar_import_dep", + ], + apex_available: ["myapex"], + min_sdk_version: "29", + } + + java_library { + name: "libbar_dep", + sdk_version: "current", + srcs: ["a.java"], + apex_available: ["myapex"], + min_sdk_version: "29", + } + + java_import { + name: "libbar_import_dep", + jars: ["libbar.jar"], + apex_available: ["myapex"], + min_sdk_version: "29", + } `) } @@ -1460,6 +1941,7 @@ func TestJavaStableSdkVersion(t *testing.T) { name: "myapex", java_libs: ["myjar"], key: "myapex.key", + updatable: false, } apex_key { name: "myapex.key", @@ -1469,7 +1951,7 @@ func TestJavaStableSdkVersion(t *testing.T) { java_library { name: "myjar", srcs: ["foo/bar/MyClass.java"], - sdk_version: "core_platform", + sdk_version: "test_current", apex_available: ["myapex"], } `, @@ -1494,6 +1976,7 @@ func TestJavaStableSdkVersion(t *testing.T) { srcs: ["foo/bar/MyClass.java"], sdk_version: "current", apex_available: ["myapex"], + min_sdk_version: "29", } `, }, @@ -1515,14 +1998,17 @@ func TestJavaStableSdkVersion(t *testing.T) { java_library { name: "myjar", srcs: ["foo/bar/MyClass.java"], - sdk_version: "core_platform", + sdk_version: "test_current", apex_available: ["myapex"], } `, }, { - name: "Updatable apex with non-stable transitive dep", - expectedError: "compiles against Android API, but dependency \"transitive-jar\" is compiling against non-public Android API.", + name: "Updatable apex with non-stable transitive dep", + // This is not actually detecting that the transitive dependency is unstable, rather it is + // detecting that the transitive dependency is building against a wider API surface than the + // module that depends on it is using. + expectedError: "compiles against Android API, but dependency \"transitive-jar\" is compiling against private API.", bp: ` apex { name: "myapex", @@ -1563,8 +2049,207 @@ func TestJavaStableSdkVersion(t *testing.T) { } } +func TestApexMinSdkVersion_ErrorIfDepIsNewer(t *testing.T) { + testApexError(t, `module "mylib2".*: should support min_sdk_version\(29\) for "myapex"`, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib"], + min_sdk_version: "29", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + shared_libs: ["mylib2"], + system_shared_libs: [], + stl: "none", + apex_available: [ + "myapex", + ], + min_sdk_version: "29", + } + + // indirect part of the apex + cc_library { + name: "mylib2", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: [ + "myapex", + ], + min_sdk_version: "30", + } + `) +} + +func TestApexMinSdkVersion_ErrorIfDepIsNewer_Java(t *testing.T) { + testApexError(t, `module "bar".*: should support min_sdk_version\(29\) for "myapex"`, ` + apex { + name: "myapex", + key: "myapex.key", + apps: ["AppFoo"], + min_sdk_version: "29", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + android_app { + name: "AppFoo", + srcs: ["foo/bar/MyClass.java"], + sdk_version: "current", + min_sdk_version: "29", + system_modules: "none", + stl: "none", + static_libs: ["bar"], + apex_available: [ "myapex" ], + } + + java_library { + name: "bar", + sdk_version: "current", + srcs: ["a.java"], + apex_available: [ "myapex" ], + } + `) +} + +func TestApexMinSdkVersion_OkayEvenWhenDepIsNewer_IfItSatisfiesApexMinSdkVersion(t *testing.T) { + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib"], + min_sdk_version: "29", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + // mylib in myapex will link to mylib2#current + // mylib in otherapex will link to mylib2(non-stub) in otherapex as well + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + shared_libs: ["mylib2"], + system_shared_libs: [], + stl: "none", + apex_available: ["myapex", "otherapex"], + min_sdk_version: "29", + } + + cc_library { + name: "mylib2", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: ["otherapex"], + stubs: { versions: ["29", "30"] }, + min_sdk_version: "30", + } + + apex { + name: "otherapex", + key: "myapex.key", + native_shared_libs: ["mylib", "mylib2"], + min_sdk_version: "30", + } + `) + expectLink := func(from, from_variant, to, to_variant string) { + ld := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld") + libFlags := ld.Args["libFlags"] + ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") + } + expectLink("mylib", "shared_apex29", "mylib2", "shared_current") + expectLink("mylib", "shared_apex30", "mylib2", "shared_apex30") +} + +func TestApexMinSdkVersion_WorksWithSdkCodename(t *testing.T) { + withSAsActiveCodeNames := android.FixtureModifyProductVariables( + func(variables android.FixtureProductVariables) { + variables.Platform_sdk_codename = proptools.StringPtr("S") + variables.Platform_version_active_codenames = []string{"S"} + }, + ) + testApexError(t, `libbar.*: should support min_sdk_version\(S\)`, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["libfoo"], + min_sdk_version: "S", + } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + cc_library { + name: "libfoo", + shared_libs: ["libbar"], + apex_available: ["myapex"], + min_sdk_version: "29", + } + cc_library { + name: "libbar", + apex_available: ["myapex"], + } + `, withSAsActiveCodeNames) +} + +func TestApexMinSdkVersion_WorksWithActiveCodenames(t *testing.T) { + withSAsActiveCodeNames := android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.Platform_sdk_codename = proptools.StringPtr("S") + variables.Platform_version_active_codenames = []string{"S", "T"} + }) + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["libfoo"], + min_sdk_version: "S", + } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + cc_library { + name: "libfoo", + shared_libs: ["libbar"], + apex_available: ["myapex"], + min_sdk_version: "S", + } + cc_library { + name: "libbar", + stubs: { + symbol_file: "libbar.map.txt", + versions: ["30", "S", "T"], + }, + } + `, withSAsActiveCodeNames) + + // ensure libfoo is linked with current version of libbar stub + libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared_apex10000") + libFlags := libfoo.Rule("ld").Args["libFlags"] + ensureContains(t, libFlags, "android_arm64_armv8-a_shared_current/libbar.so") +} + func TestFilesInSubDir(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", @@ -1572,6 +2257,7 @@ func TestFilesInSubDir(t *testing.T) { binaries: ["mybin"], prebuilts: ["myetc"], compile_multilib: "both", + updatable: false, } apex_key { @@ -1625,13 +2311,20 @@ func TestFilesInSubDir(t *testing.T) { ensureListContains(t, dirs, "bin/foo/bar") } -func TestUseVendor(t *testing.T) { - ctx, _ := testApex(t, ` +func TestFilesInSubDirWhenNativeBridgeEnabled(t *testing.T) { + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", - native_shared_libs: ["mylib"], - use_vendor: true, + multilib: { + both: { + native_shared_libs: ["mylib"], + binaries: ["mybin"], + }, + }, + compile_multilib: "both", + native_bridge_supported: true, + updatable: false, } apex_key { @@ -1642,82 +2335,223 @@ func TestUseVendor(t *testing.T) { cc_library { name: "mylib", - srcs: ["mylib.cpp"], - shared_libs: ["mylib2"], + relative_install_path: "foo/bar", system_shared_libs: [], - vendor_available: true, stl: "none", apex_available: [ "myapex" ], + native_bridge_supported: true, } - cc_library { - name: "mylib2", - srcs: ["mylib.cpp"], + cc_binary { + name: "mybin", + relative_install_path: "foo/bar", system_shared_libs: [], - vendor_available: true, + static_executable: true, stl: "none", apex_available: [ "myapex" ], + native_bridge_supported: true, + compile_multilib: "both", // default is "first" for binary + multilib: { + lib64: { + suffix: "64", + }, + }, } - `, func(fs map[string][]byte, config android.Config) { - setUseVendorAllowListForTest(config, []string{"myapex"}) + `, withNativeBridgeEnabled) + ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + "bin/foo/bar/mybin", + "bin/foo/bar/mybin64", + "bin/arm/foo/bar/mybin", + "bin/arm64/foo/bar/mybin64", + "lib/foo/bar/mylib.so", + "lib/arm/foo/bar/mylib.so", + "lib64/foo/bar/mylib.so", + "lib64/arm64/foo/bar/mylib.so", }) +} - inputsList := []string{} - for _, i := range ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().BuildParamsForTests() { - for _, implicit := range i.Implicits { - inputsList = append(inputsList, implicit.String()) +func TestVendorApex(t *testing.T) { + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + binaries: ["mybin"], + vendor: true, + updatable: false, } - } - inputsString := strings.Join(inputsList, " ") + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + cc_binary { + name: "mybin", + vendor: true, + shared_libs: ["libfoo"], + } + cc_library { + name: "libfoo", + proprietary: true, + } + `) - // ensure that the apex includes vendor variants of the direct and indirect deps - ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_myapex/mylib.so") - ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_myapex/mylib2.so") + ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + "bin/mybin", + "lib64/libfoo.so", + // TODO(b/159195575): Add an option to use VNDK libs from VNDK APEX + "lib64/libc++.so", + }) - // ensure that the apex does not include core variants - ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_myapex/mylib.so") - ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_myapex/mylib2.so") + apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + data := android.AndroidMkDataForTest(t, ctx, apexBundle) + name := apexBundle.BaseModuleName() + prefix := "TARGET_" + var builder strings.Builder + data.Custom(&builder, name, prefix, "", data) + androidMk := android.StringRelativeToTop(ctx.Config(), builder.String()) + installPath := "out/target/product/test_device/vendor/apex" + ensureContains(t, androidMk, "LOCAL_MODULE_PATH := "+installPath) + + apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") + requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"]) + ensureListNotContains(t, requireNativeLibs, ":vndk") } -func TestUseVendorRestriction(t *testing.T) { - testApexError(t, `module "myapex" .*: use_vendor: not allowed`, ` +func TestVendorApex_use_vndk_as_stable(t *testing.T) { + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", - use_vendor: true, + binaries: ["mybin"], + vendor: true, + use_vndk_as_stable: true, + updatable: false, } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } - `, func(fs map[string][]byte, config android.Config) { - setUseVendorAllowListForTest(config, []string{""}) + cc_binary { + name: "mybin", + vendor: true, + shared_libs: ["libvndk", "libvendor"], + } + cc_library { + name: "libvndk", + vndk: { + enabled: true, + }, + vendor_available: true, + product_available: true, + } + cc_library { + name: "libvendor", + vendor: true, + } + `) + + vendorVariant := "android_vendor.29_arm64_armv8-a" + + ldRule := ctx.ModuleForTests("mybin", vendorVariant+"_apex10000").Rule("ld") + libs := names(ldRule.Args["libFlags"]) + // VNDK libs(libvndk/libc++) as they are + ensureListContains(t, libs, "out/soong/.intermediates/libvndk/"+vendorVariant+"_shared/libvndk.so") + ensureListContains(t, libs, "out/soong/.intermediates/"+cc.DefaultCcCommonTestModulesDir+"libc++/"+vendorVariant+"_shared/libc++.so") + // non-stable Vendor libs as APEX variants + ensureListContains(t, libs, "out/soong/.intermediates/libvendor/"+vendorVariant+"_shared_apex10000/libvendor.so") + + // VNDK libs are not included when use_vndk_as_stable: true + ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + "bin/mybin", + "lib64/libvendor.so", }) - // no error with allow list - testApex(t, ` + + apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") + requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"]) + ensureListContains(t, requireNativeLibs, ":vndk") +} + +func TestProductVariant(t *testing.T) { + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", - use_vendor: true, + updatable: false, + product_specific: true, + binaries: ["foo"], } + apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } - `, func(fs map[string][]byte, config android.Config) { - setUseVendorAllowListForTest(config, []string{"myapex"}) - }) + + cc_binary { + name: "foo", + product_available: true, + apex_available: ["myapex"], + srcs: ["foo.cpp"], + } + `, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.ProductVndkVersion = proptools.StringPtr("current") + }), + ) + + cflags := strings.Fields( + ctx.ModuleForTests("foo", "android_product.29_arm64_armv8-a_apex10000").Rule("cc").Args["cFlags"]) + ensureListContains(t, cflags, "-D__ANDROID_VNDK__") + ensureListContains(t, cflags, "-D__ANDROID_APEX__") + ensureListContains(t, cflags, "-D__ANDROID_PRODUCT__") + ensureListNotContains(t, cflags, "-D__ANDROID_VENDOR__") } -func TestUseVendorFailsIfNotVendorAvailable(t *testing.T) { - testApexError(t, `dependency "mylib" of "myapex" missing variant:\n.*image:vendor`, ` +func TestApex_withPrebuiltFirmware(t *testing.T) { + testCases := []struct { + name string + additionalProp string + }{ + {"system apex with prebuilt_firmware", ""}, + {"vendor apex with prebuilt_firmware", "vendor: true,"}, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + prebuilts: ["myfirmware"], + updatable: false, + `+tc.additionalProp+` + } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + prebuilt_firmware { + name: "myfirmware", + src: "myfirmware.bin", + filename_from_src: true, + `+tc.additionalProp+` + } + `) + ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + "etc/firmware/myfirmware.bin", + }) + }) + } +} + +func TestAndroidMk_VendorApexRequired(t *testing.T) { + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", + vendor: true, native_shared_libs: ["mylib"], - use_vendor: true, + updatable: false, } apex_key { @@ -1728,19 +2562,57 @@ func TestUseVendorFailsIfNotVendorAvailable(t *testing.T) { cc_library { name: "mylib", - srcs: ["mylib.cpp"], - system_shared_libs: [], - stl: "none", + vendor_available: true, } `) + + apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + data := android.AndroidMkDataForTest(t, ctx, apexBundle) + name := apexBundle.BaseModuleName() + prefix := "TARGET_" + var builder strings.Builder + data.Custom(&builder, name, prefix, "", data) + androidMk := builder.String() + ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += libc.vendor libm.vendor libdl.vendor\n") +} + +func TestAndroidMkWritesCommonProperties(t *testing.T) { + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + vintf_fragments: ["fragment.xml"], + init_rc: ["init.rc"], + updatable: false, + } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + cc_binary { + name: "mybin", + } + `) + + apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + data := android.AndroidMkDataForTest(t, ctx, apexBundle) + name := apexBundle.BaseModuleName() + prefix := "TARGET_" + var builder strings.Builder + data.Custom(&builder, name, prefix, "", data) + androidMk := builder.String() + ensureContains(t, androidMk, "LOCAL_FULL_VINTF_FRAGMENTS := fragment.xml\n") + ensureContains(t, androidMk, "LOCAL_FULL_INIT_RC := init.rc\n") } func TestStaticLinking(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], + updatable: false, } apex_key { @@ -1780,13 +2652,14 @@ func TestStaticLinking(t *testing.T) { } func TestKeys(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex_keytest", key: "myapex.key", certificate: ":myapex.certificate", native_shared_libs: ["mylib"], file_contexts: ":myapex-file_contexts", + updatable: false, } cc_library { @@ -1818,12 +2691,12 @@ func TestKeys(t *testing.T) { // check the APEX keys keys := ctx.ModuleForTests("myapex.key", "android_common").Module().(*apexKey) - if keys.public_key_file.String() != "vendor/foo/devkeys/testkey.avbpubkey" { - t.Errorf("public key %q is not %q", keys.public_key_file.String(), + if keys.publicKeyFile.String() != "vendor/foo/devkeys/testkey.avbpubkey" { + t.Errorf("public key %q is not %q", keys.publicKeyFile.String(), "vendor/foo/devkeys/testkey.avbpubkey") } - if keys.private_key_file.String() != "vendor/foo/devkeys/testkey.pem" { - t.Errorf("private key %q is not %q", keys.private_key_file.String(), + if keys.privateKeyFile.String() != "vendor/foo/devkeys/testkey.pem" { + t.Errorf("private key %q is not %q", keys.privateKeyFile.String(), "vendor/foo/devkeys/testkey.pem") } @@ -1837,10 +2710,11 @@ func TestKeys(t *testing.T) { func TestCertificate(t *testing.T) { t.Run("if unspecified, it defaults to DefaultAppCertificate", func(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", + updatable: false, } apex_key { name: "myapex.key", @@ -1854,11 +2728,12 @@ func TestCertificate(t *testing.T) { } }) t.Run("override when unspecified", func(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex_keytest", key: "myapex.key", file_contexts: ":myapex-file_contexts", + updatable: false, } apex_key { name: "myapex.key", @@ -1876,11 +2751,12 @@ func TestCertificate(t *testing.T) { } }) t.Run("if specified as :module, it respects the prop", func(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", certificate: ":myapex.certificate", + updatable: false, } apex_key { name: "myapex.key", @@ -1898,12 +2774,13 @@ func TestCertificate(t *testing.T) { } }) t.Run("override when specifiec as <:module>", func(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex_keytest", key: "myapex.key", file_contexts: ":myapex-file_contexts", certificate: ":myapex.certificate", + updatable: false, } apex_key { name: "myapex.key", @@ -1921,11 +2798,12 @@ func TestCertificate(t *testing.T) { } }) t.Run("if specified as name, finds it from DefaultDevKeyDir", func(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", certificate: "testkey", + updatable: false, } apex_key { name: "myapex.key", @@ -1939,12 +2817,13 @@ func TestCertificate(t *testing.T) { } }) t.Run("override when specified as <name>", func(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex_keytest", key: "myapex.key", file_contexts: ":myapex-file_contexts", certificate: "testkey", + updatable: false, } apex_key { name: "myapex.key", @@ -1964,11 +2843,12 @@ func TestCertificate(t *testing.T) { } func TestMacro(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib", "mylib2"], + updatable: false, } apex { @@ -1994,6 +2874,7 @@ func TestMacro(t *testing.T) { "otherapex", ], recovery_available: true, + min_sdk_version: "29", } cc_library { name: "mylib2", @@ -2004,29 +2885,68 @@ func TestMacro(t *testing.T) { "myapex", "otherapex", ], + static_libs: ["mylib3"], + recovery_available: true, + min_sdk_version: "29", + } + cc_library { + name: "mylib3", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: [ + "myapex", + "otherapex", + ], use_apex_name_macro: true, + recovery_available: true, + min_sdk_version: "29", } `) // non-APEX variant does not have __ANDROID_APEX__ defined mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") - ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MIN_SDK_VERSION__") // APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined - mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] + mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") - ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=10000") + ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_MIN_SDK_VERSION__=10000") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") // APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined - mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"] + mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex29").Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") - ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=29") + ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_MIN_SDK_VERSION__=29") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") - // When cc_library sets use_apex_name_macro: true - // apex variants define additional macro to distinguish which apex variant it is built for + // When a cc_library sets use_apex_name_macro: true each apex gets a unique variant and + // each variant defines additional macros to distinguish which apex variant it is built for + + // non-APEX variant does not have __ANDROID_APEX__ defined + mylibCFlags = ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") + + // APEX variant has __ANDROID_APEX__ defined + mylibCFlags = ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] + ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") + ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") + + // APEX variant has __ANDROID_APEX__ defined + mylibCFlags = ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"] + ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") + ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") + + // recovery variant does not set __ANDROID_APEX_MIN_SDK_VERSION__ + mylibCFlags = ctx.ModuleForTests("mylib3", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MIN_SDK_VERSION__") + + // When a dependency of a cc_library sets use_apex_name_macro: true each apex gets a unique + // variant. // non-APEX variant does not have __ANDROID_APEX__ defined mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] @@ -2035,27 +2955,28 @@ func TestMacro(t *testing.T) { // APEX variant has __ANDROID_APEX__ defined mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") - ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") // APEX variant has __ANDROID_APEX__ defined mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") - ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") - // recovery variant does not set __ANDROID_SDK_VERSION__ - mylibCFlags = ctx.ModuleForTests("mylib", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + // recovery variant does not set __ANDROID_APEX_MIN_SDK_VERSION__ + mylibCFlags = ctx.ModuleForTests("mylib2", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"] ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") - ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MIN_SDK_VERSION__") } func TestHeaderLibsDependency(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], + updatable: false, } apex_key { @@ -2194,14 +3115,15 @@ func ensureExactContents(t *testing.T, ctx *android.TestContext, moduleName, var } func TestVndkApexCurrent(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex_vndk { - name: "myapex", - key: "myapex.key", + name: "com.android.vndk.current", + key: "com.android.vndk.current.key", + updatable: false, } apex_key { - name: "myapex.key", + name: "com.android.vndk.current.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } @@ -2210,51 +3132,55 @@ func TestVndkApexCurrent(t *testing.T) { name: "libvndk", srcs: ["mylib.cpp"], vendor_available: true, + product_available: true, vndk: { enabled: true, }, system_shared_libs: [], stl: "none", - apex_available: [ "myapex" ], + apex_available: [ "com.android.vndk.current" ], } cc_library { name: "libvndksp", srcs: ["mylib.cpp"], vendor_available: true, + product_available: true, vndk: { enabled: true, support_system_process: true, }, system_shared_libs: [], stl: "none", - apex_available: [ "myapex" ], + apex_available: [ "com.android.vndk.current" ], } `+vndkLibrariesTxtFiles("current")) - ensureExactContents(t, ctx, "myapex", "android_common_image", []string{ + ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{ "lib/libvndk.so", "lib/libvndksp.so", "lib/libc++.so", "lib64/libvndk.so", "lib64/libvndksp.so", "lib64/libc++.so", - "etc/llndk.libraries.VER.txt", - "etc/vndkcore.libraries.VER.txt", - "etc/vndksp.libraries.VER.txt", - "etc/vndkprivate.libraries.VER.txt", + "etc/llndk.libraries.29.txt", + "etc/vndkcore.libraries.29.txt", + "etc/vndksp.libraries.29.txt", + "etc/vndkprivate.libraries.29.txt", + "etc/vndkproduct.libraries.29.txt", }) } func TestVndkApexWithPrebuilt(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex_vndk { - name: "myapex", - key: "myapex.key", + name: "com.android.vndk.current", + key: "com.android.vndk.current.key", + updatable: false, } apex_key { - name: "myapex.key", + name: "com.android.vndk.current.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } @@ -2263,18 +3189,20 @@ func TestVndkApexWithPrebuilt(t *testing.T) { name: "libvndk", srcs: ["libvndk.so"], vendor_available: true, + product_available: true, vndk: { enabled: true, }, system_shared_libs: [], stl: "none", - apex_available: [ "myapex" ], + apex_available: [ "com.android.vndk.current" ], } cc_prebuilt_library_shared { name: "libvndk.arm", srcs: ["libvndk.arm.so"], vendor_available: true, + product_available: true, vndk: { enabled: true, }, @@ -2286,15 +3214,14 @@ func TestVndkApexWithPrebuilt(t *testing.T) { }, system_shared_libs: [], stl: "none", - apex_available: [ "myapex" ], + apex_available: [ "com.android.vndk.current" ], } `+vndkLibrariesTxtFiles("current"), withFiles(map[string][]byte{ "libvndk.so": nil, "libvndk.arm.so": nil, })) - - ensureExactContents(t, ctx, "myapex", "android_common_image", []string{ + ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{ "lib/libvndk.so", "lib/libvndk.arm.so", "lib64/libvndk.so", @@ -2307,15 +3234,15 @@ func TestVndkApexWithPrebuilt(t *testing.T) { func vndkLibrariesTxtFiles(vers ...string) (result string) { for _, v := range vers { if v == "current" { - for _, txt := range []string{"llndk", "vndkcore", "vndksp", "vndkprivate"} { + for _, txt := range []string{"llndk", "vndkcore", "vndksp", "vndkprivate", "vndkproduct"} { result += ` - vndk_libraries_txt { + ` + txt + `_libraries_txt { name: "` + txt + `.libraries.txt", } ` } } else { - for _, txt := range []string{"llndk", "vndkcore", "vndksp", "vndkprivate"} { + for _, txt := range []string{"llndk", "vndkcore", "vndksp", "vndkprivate", "vndkproduct"} { result += ` prebuilt_etc { name: "` + txt + `.libraries.` + v + `.txt", @@ -2329,12 +3256,13 @@ func vndkLibrariesTxtFiles(vers ...string) (result string) { } func TestVndkApexVersion(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex_vndk { - name: "myapex_v27", + name: "com.android.vndk.v27", key: "myapex.key", file_contexts: ":myapex-file_contexts", vndk_version: "27", + updatable: false, } apex_key { @@ -2347,6 +3275,7 @@ func TestVndkApexVersion(t *testing.T) { name: "libvndk27", version: "27", vendor_available: true, + product_available: true, vndk: { enabled: true, }, @@ -2359,13 +3288,14 @@ func TestVndkApexVersion(t *testing.T) { srcs: ["libvndk27_arm64.so"], }, }, - apex_available: [ "myapex_v27" ], + apex_available: [ "com.android.vndk.v27" ], } vndk_prebuilt_shared { name: "libvndk27", version: "27", vendor_available: true, + product_available: true, vndk: { enabled: true, }, @@ -2387,71 +3317,27 @@ func TestVndkApexVersion(t *testing.T) { "libvndk27_x86_64.so": nil, })) - ensureExactContents(t, ctx, "myapex_v27", "android_common_image", []string{ + ensureExactContents(t, ctx, "com.android.vndk.v27", "android_common_image", []string{ "lib/libvndk27_arm.so", "lib64/libvndk27_arm64.so", "etc/*", }) } -func TestVndkApexErrorWithDuplicateVersion(t *testing.T) { - testApexError(t, `module "myapex_v27.*" .*: vndk_version: 27 is already defined in "myapex_v27.*"`, ` - apex_vndk { - name: "myapex_v27", - key: "myapex.key", - file_contexts: ":myapex-file_contexts", - vndk_version: "27", - } - apex_vndk { - name: "myapex_v27_other", - key: "myapex.key", - file_contexts: ":myapex-file_contexts", - vndk_version: "27", - } - - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } - - cc_library { - name: "libvndk", - srcs: ["mylib.cpp"], - vendor_available: true, - vndk: { - enabled: true, - }, - system_shared_libs: [], - stl: "none", - } - - vndk_prebuilt_shared { - name: "libvndk", - version: "27", - vendor_available: true, - vndk: { - enabled: true, - }, - srcs: ["libvndk.so"], - } - `, withFiles(map[string][]byte{ - "libvndk.so": nil, - })) -} - func TestVndkApexNameRule(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex_vndk { - name: "myapex", + name: "com.android.vndk.current", key: "myapex.key", file_contexts: ":myapex-file_contexts", + updatable: false, } apex_vndk { - name: "myapex_v28", + name: "com.android.vndk.v28", key: "myapex.key", file_contexts: ":myapex-file_contexts", vndk_version: "28", + updatable: false, } apex_key { name: "myapex.key", @@ -2467,20 +3353,21 @@ func TestVndkApexNameRule(t *testing.T) { } } - assertApexName("com.android.vndk.vVER", "myapex") - assertApexName("com.android.vndk.v28", "myapex_v28") + assertApexName("com.android.vndk.v29", "com.android.vndk.current") + assertApexName("com.android.vndk.v28", "com.android.vndk.v28") } func TestVndkApexSkipsNativeBridgeSupportedModules(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex_vndk { - name: "myapex", - key: "myapex.key", + name: "com.android.vndk.current", + key: "com.android.vndk.current.key", file_contexts: ":myapex-file_contexts", + updatable: false, } apex_key { - name: "myapex.key", + name: "com.android.vndk.current.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } @@ -2489,6 +3376,7 @@ func TestVndkApexSkipsNativeBridgeSupportedModules(t *testing.T) { name: "libvndk", srcs: ["mylib.cpp"], vendor_available: true, + product_available: true, native_bridge_supported: true, host_supported: true, vndk: { @@ -2496,19 +3384,12 @@ func TestVndkApexSkipsNativeBridgeSupportedModules(t *testing.T) { }, system_shared_libs: [], stl: "none", - apex_available: [ "myapex" ], + apex_available: [ "com.android.vndk.current" ], } `+vndkLibrariesTxtFiles("current"), - withTargets(map[android.OsType][]android.Target{ - android.Android: []android.Target{ - {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""}, - {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""}, - {Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "arm64", NativeBridgeRelativePath: "x86_64"}, - {Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "arm", NativeBridgeRelativePath: "x86"}, - }, - })) + withNativeBridgeEnabled) - ensureExactContents(t, ctx, "myapex", "android_common_image", []string{ + ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{ "lib/libvndk.so", "lib64/libvndk.so", "lib/libc++.so", @@ -2518,16 +3399,16 @@ func TestVndkApexSkipsNativeBridgeSupportedModules(t *testing.T) { } func TestVndkApexDoesntSupportNativeBridgeSupported(t *testing.T) { - testApexError(t, `module "myapex" .*: native_bridge_supported: .* doesn't support native bridge binary`, ` + testApexError(t, `module "com.android.vndk.current" .*: native_bridge_supported: .* doesn't support native bridge binary`, ` apex_vndk { - name: "myapex", - key: "myapex.key", + name: "com.android.vndk.current", + key: "com.android.vndk.current.key", file_contexts: ":myapex-file_contexts", native_bridge_supported: true, } apex_key { - name: "myapex.key", + name: "com.android.vndk.current.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } @@ -2536,6 +3417,7 @@ func TestVndkApexDoesntSupportNativeBridgeSupported(t *testing.T) { name: "libvndk", srcs: ["mylib.cpp"], vendor_available: true, + product_available: true, native_bridge_supported: true, host_supported: true, vndk: { @@ -2548,12 +3430,13 @@ func TestVndkApexDoesntSupportNativeBridgeSupported(t *testing.T) { } func TestVndkApexWithBinder32(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex_vndk { - name: "myapex_v27", + name: "com.android.vndk.v27", key: "myapex.key", file_contexts: ":myapex-file_contexts", vndk_version: "27", + updatable: false, } apex_key { @@ -2567,6 +3450,7 @@ func TestVndkApexWithBinder32(t *testing.T) { version: "27", target_arch: "arm", vendor_available: true, + product_available: true, vndk: { enabled: true, }, @@ -2583,6 +3467,7 @@ func TestVndkApexWithBinder32(t *testing.T) { target_arch: "arm", binder32bit: true, vendor_available: true, + product_available: true, vndk: { enabled: true, }, @@ -2591,7 +3476,7 @@ func TestVndkApexWithBinder32(t *testing.T) { srcs: ["libvndk27binder32.so"], } }, - apex_available: [ "myapex_v27" ], + apex_available: [ "com.android.vndk.v27" ], } `+vndkLibrariesTxtFiles("27"), withFiles(map[string][]byte{ @@ -2601,25 +3486,63 @@ func TestVndkApexWithBinder32(t *testing.T) { withBinder32bit, withTargets(map[android.OsType][]android.Target{ android.Android: []android.Target{ - {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""}, + {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, + NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""}, }, }), ) - ensureExactContents(t, ctx, "myapex_v27", "android_common_image", []string{ + ensureExactContents(t, ctx, "com.android.vndk.v27", "android_common_image", []string{ "lib/libvndk27binder32.so", "etc/*", }) } +func TestVndkApexShouldNotProvideNativeLibs(t *testing.T) { + ctx := testApex(t, ` + apex_vndk { + name: "com.android.vndk.current", + key: "com.android.vndk.current.key", + file_contexts: ":myapex-file_contexts", + updatable: false, + } + + apex_key { + name: "com.android.vndk.current.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "libz", + vendor_available: true, + product_available: true, + vndk: { + enabled: true, + }, + stubs: { + symbol_file: "libz.map.txt", + versions: ["30"], + } + } + `+vndkLibrariesTxtFiles("current"), withFiles(map[string][]byte{ + "libz.map.txt": nil, + })) + + apexManifestRule := ctx.ModuleForTests("com.android.vndk.current", "android_common_image").Rule("apexManifestRule") + provideNativeLibs := names(apexManifestRule.Args["provideNativeLibs"]) + ensureListEmpty(t, provideNativeLibs) +} + func TestDependenciesInApexManifest(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex_nodep", key: "myapex.key", native_shared_libs: ["lib_nodep"], compile_multilib: "both", file_contexts: ":myapex-file_contexts", + updatable: false, } apex { @@ -2628,6 +3551,7 @@ func TestDependenciesInApexManifest(t *testing.T) { native_shared_libs: ["lib_dep"], compile_multilib: "both", file_contexts: ":myapex-file_contexts", + updatable: false, } apex { @@ -2636,6 +3560,7 @@ func TestDependenciesInApexManifest(t *testing.T) { native_shared_libs: ["libfoo"], compile_multilib: "both", file_contexts: ":myapex-file_contexts", + updatable: false, } apex { @@ -2644,6 +3569,7 @@ func TestDependenciesInApexManifest(t *testing.T) { native_shared_libs: ["lib_dep", "libfoo"], compile_multilib: "both", file_contexts: ":myapex-file_contexts", + updatable: false, } apex_key { @@ -2717,12 +3643,13 @@ func TestDependenciesInApexManifest(t *testing.T) { } func TestApexName(t *testing.T) { - ctx, config := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", apex_name: "com.android.myapex", native_shared_libs: ["mylib"], + updatable: false, } apex_key { @@ -2743,14 +3670,14 @@ func TestApexName(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + module := ctx.ModuleForTests("myapex", "android_common_com.android.myapex_image") apexManifestRule := module.Rule("apexManifestRule") ensureContains(t, apexManifestRule.Args["opt"], "-v name com.android.myapex") apexRule := module.Rule("apexRule") ensureContains(t, apexRule.Args["opt_flags"], "--do_not_check_keyname") - apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) - data := android.AndroidMkDataForTest(t, config, "", apexBundle) + apexBundle := module.Module().(*apexBundle) + data := android.AndroidMkDataForTest(t, ctx, apexBundle) name := apexBundle.BaseModuleName() prefix := "TARGET_" var builder strings.Builder @@ -2761,11 +3688,12 @@ func TestApexName(t *testing.T) { } func TestNonTestApex(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib_common"], + updatable: false, } apex_key { @@ -2798,7 +3726,7 @@ func TestNonTestApex(t *testing.T) { ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned") // Ensure that apex variant is created for the direct dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_apex10000") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.apex/lib64/mylib_common.so") @@ -2806,21 +3734,19 @@ func TestNonTestApex(t *testing.T) { // Ensure that the platform variant ends with _shared ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared") - if !android.InAnyApex("mylib_common") { + if !ctx.ModuleForTests("mylib_common", "android_arm64_armv8-a_shared_apex10000").Module().(*cc.Module).InAnyApex() { t.Log("Found mylib_common not in any apex!") t.Fail() } } func TestTestApex(t *testing.T) { - if android.InAnyApex("mylib_common_test") { - t.Fatal("mylib_common_test must not be used in any other tests since this checks that global state is not updated in an illegal way!") - } - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex_test { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib_common_test"], + updatable: false, } apex_key { @@ -2854,7 +3780,7 @@ func TestTestApex(t *testing.T) { ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned") // Ensure that apex variant is created for the direct dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_shared_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_shared_apex10000") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.apex/lib64/mylib_common_test.so") @@ -2864,10 +3790,11 @@ func TestTestApex(t *testing.T) { } func TestApexWithTarget(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", + updatable: false, multilib: { first: { native_shared_libs: ["mylib_common"], @@ -2938,9 +3865,9 @@ func TestApexWithTarget(t *testing.T) { ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned") // Ensure that apex variant is created for the direct dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex") - ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_myapex") - ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_apex10000") + ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") @@ -2953,12 +3880,72 @@ func TestApexWithTarget(t *testing.T) { ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared") } +func TestApexWithArch(t *testing.T) { + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + updatable: false, + arch: { + arm64: { + native_shared_libs: ["mylib.arm64"], + }, + x86_64: { + native_shared_libs: ["mylib.x64"], + }, + } + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib.arm64", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + // TODO: remove //apex_available:platform + apex_available: [ + "//apex_available:platform", + "myapex", + ], + } + + cc_library { + name: "mylib.x64", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + // TODO: remove //apex_available:platform + apex_available: [ + "//apex_available:platform", + "myapex", + ], + } + `) + + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + copyCmds := apexRule.Args["copy_commands"] + + // Ensure that apex variant is created for the direct dep + ensureListContains(t, ctx.ModuleVariantsForTests("mylib.arm64"), "android_arm64_armv8-a_shared_apex10000") + ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib.x64"), "android_arm64_armv8-a_shared_apex10000") + + // Ensure that both direct and indirect deps are copied into apex + ensureContains(t, copyCmds, "image.apex/lib64/mylib.arm64.so") + ensureNotContains(t, copyCmds, "image.apex/lib64/mylib.x64.so") +} + func TestApexWithShBinary(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", binaries: ["myscript"], + updatable: false, } apex_key { @@ -2994,10 +3981,11 @@ func TestApexInVariousPartition(t *testing.T) { } for _, tc := range testcases { t.Run(tc.propName+":"+tc.parition, func(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", + updatable: false, `+tc.propName+` } @@ -3009,15 +3997,15 @@ func TestApexInVariousPartition(t *testing.T) { `) apex := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) - expected := buildDir + "/target/product/test_device/" + tc.parition + "/apex" - actual := apex.installDir.String() + expected := "out/soong/target/product/test_device/" + tc.parition + "/apex" + actual := apex.installDir.RelativeToTop().String() if actual != expected { t.Errorf("wrong install path. expected %q. actual %q", expected, actual) } flattened := ctx.ModuleForTests("myapex", "android_common_myapex_flattened").Module().(*apexBundle) - expected = buildDir + "/target/product/test_device/" + tc.flattenedPartition + "/apex" - actual = flattened.installDir.String() + expected = "out/soong/target/product/test_device/" + tc.flattenedPartition + "/apex" + actual = flattened.installDir.RelativeToTop().String() if actual != expected { t.Errorf("wrong install path. expected %q. actual %q", expected, actual) } @@ -3025,114 +4013,113 @@ func TestApexInVariousPartition(t *testing.T) { } } -func TestFileContexts(t *testing.T) { - ctx, _ := testApex(t, ` - apex { - name: "myapex", - key: "myapex.key", - } +func TestFileContexts_FindInDefaultLocationIfNotSet(t *testing.T) { + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + updatable: false, + } - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } `) module := ctx.ModuleForTests("myapex", "android_common_myapex_image") - apexRule := module.Rule("apexRule") - actual := apexRule.Args["file_contexts"] - expected := "system/sepolicy/apex/myapex-file_contexts" - if actual != expected { - t.Errorf("wrong file_contexts. expected %q. actual %q", expected, actual) - } + rule := module.Output("file_contexts") + ensureContains(t, rule.RuleParams.Command, "cat system/sepolicy/apex/myapex-file_contexts") +} +func TestFileContexts_ShouldBeUnderSystemSepolicyForSystemApexes(t *testing.T) { testApexError(t, `"myapex" .*: file_contexts: should be under system/sepolicy`, ` - apex { - name: "myapex", - key: "myapex.key", - file_contexts: "my_own_file_contexts", - } + apex { + name: "myapex", + key: "myapex.key", + file_contexts: "my_own_file_contexts", + updatable: false, + } - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } `, withFiles(map[string][]byte{ "my_own_file_contexts": nil, })) +} +func TestFileContexts_ProductSpecificApexes(t *testing.T) { testApexError(t, `"myapex" .*: file_contexts: cannot find`, ` - apex { - name: "myapex", - key: "myapex.key", - product_specific: true, - file_contexts: "product_specific_file_contexts", - } + apex { + name: "myapex", + key: "myapex.key", + product_specific: true, + file_contexts: "product_specific_file_contexts", + updatable: false, + } - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } `) - ctx, _ = testApex(t, ` - apex { - name: "myapex", - key: "myapex.key", - product_specific: true, - file_contexts: "product_specific_file_contexts", - } + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + product_specific: true, + file_contexts: "product_specific_file_contexts", + updatable: false, + } - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } `, withFiles(map[string][]byte{ "product_specific_file_contexts": nil, })) - module = ctx.ModuleForTests("myapex", "android_common_myapex_image") - apexRule = module.Rule("apexRule") - actual = apexRule.Args["file_contexts"] - expected = "product_specific_file_contexts" - if actual != expected { - t.Errorf("wrong file_contexts. expected %q. actual %q", expected, actual) - } + module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + rule := module.Output("file_contexts") + ensureContains(t, rule.RuleParams.Command, "cat product_specific_file_contexts") +} - ctx, _ = testApex(t, ` - apex { - name: "myapex", - key: "myapex.key", - product_specific: true, - file_contexts: ":my-file-contexts", - } +func TestFileContexts_SetViaFileGroup(t *testing.T) { + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + product_specific: true, + file_contexts: ":my-file-contexts", + updatable: false, + } - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } - filegroup { - name: "my-file-contexts", - srcs: ["product_specific_file_contexts"], - } + filegroup { + name: "my-file-contexts", + srcs: ["product_specific_file_contexts"], + } `, withFiles(map[string][]byte{ "product_specific_file_contexts": nil, })) - module = ctx.ModuleForTests("myapex", "android_common_myapex_image") - apexRule = module.Rule("apexRule") - actual = apexRule.Args["file_contexts"] - expected = "product_specific_file_contexts" - if actual != expected { - t.Errorf("wrong file_contexts. expected %q. actual %q", expected, actual) - } + module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + rule := module.Output("file_contexts") + ensureContains(t, rule.RuleParams.Command, "cat product_specific_file_contexts") } func TestApexKeyFromOtherModule(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex_key { name: "myapex.key", public_key: ":my.avbpubkey", @@ -3153,19 +4140,19 @@ func TestApexKeyFromOtherModule(t *testing.T) { apex_key := ctx.ModuleForTests("myapex.key", "android_common").Module().(*apexKey) expected_pubkey := "testkey2.avbpubkey" - actual_pubkey := apex_key.public_key_file.String() + actual_pubkey := apex_key.publicKeyFile.String() if actual_pubkey != expected_pubkey { t.Errorf("wrong public key path. expected %q. actual %q", expected_pubkey, actual_pubkey) } expected_privkey := "testkey2.pem" - actual_privkey := apex_key.private_key_file.String() + actual_privkey := apex_key.privateKeyFile.String() if actual_privkey != expected_privkey { t.Errorf("wrong private key path. expected %q. actual %q", expected_privkey, actual_privkey) } } func TestPrebuilt(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` prebuilt_apex { name: "myapex", arch: { @@ -3179,7 +4166,7 @@ func TestPrebuilt(t *testing.T) { } `) - prebuilt := ctx.ModuleForTests("myapex", "android_common").Module().(*Prebuilt) + prebuilt := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*Prebuilt) expectedInput := "myapex-arm64.apex" if prebuilt.inputApex.String() != expectedInput { @@ -3187,8 +4174,16 @@ func TestPrebuilt(t *testing.T) { } } +func TestPrebuiltMissingSrc(t *testing.T) { + testApexError(t, `module "myapex" variant "android_common_myapex".*: prebuilt_apex does not support "arm64_armv8-a"`, ` + prebuilt_apex { + name: "myapex", + } + `) +} + func TestPrebuiltFilenameOverride(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` prebuilt_apex { name: "myapex", src: "myapex-arm.apex", @@ -3196,7 +4191,7 @@ func TestPrebuiltFilenameOverride(t *testing.T) { } `) - p := ctx.ModuleForTests("myapex", "android_common").Module().(*Prebuilt) + p := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*Prebuilt) expected := "notmyapex.apex" if p.installFilename != expected { @@ -3205,7 +4200,7 @@ func TestPrebuiltFilenameOverride(t *testing.T) { } func TestPrebuiltOverrides(t *testing.T) { - ctx, config := testApex(t, ` + ctx := testApex(t, ` prebuilt_apex { name: "myapex.prebuilt", src: "myapex-arm.apex", @@ -3215,20 +4210,646 @@ func TestPrebuiltOverrides(t *testing.T) { } `) - p := ctx.ModuleForTests("myapex.prebuilt", "android_common").Module().(*Prebuilt) + p := ctx.ModuleForTests("myapex.prebuilt", "android_common_myapex.prebuilt").Module().(*Prebuilt) expected := []string{"myapex"} - actual := android.AndroidMkEntriesForTest(t, config, "", p)[0].EntryMap["LOCAL_OVERRIDES_MODULES"] + actual := android.AndroidMkEntriesForTest(t, ctx, p)[0].EntryMap["LOCAL_OVERRIDES_MODULES"] if !reflect.DeepEqual(actual, expected) { t.Errorf("Incorrect LOCAL_OVERRIDES_MODULES value '%s', expected '%s'", actual, expected) } } +func TestPrebuiltApexName(t *testing.T) { + testApex(t, ` + prebuilt_apex { + name: "com.company.android.myapex", + apex_name: "com.android.myapex", + src: "company-myapex-arm.apex", + } + `).ModuleForTests("com.company.android.myapex", "android_common_com.android.myapex") + + testApex(t, ` + apex_set { + name: "com.company.android.myapex", + apex_name: "com.android.myapex", + set: "company-myapex.apks", + } + `).ModuleForTests("com.company.android.myapex", "android_common_com.android.myapex") +} + +func TestPrebuiltApexNameWithPlatformBootclasspath(t *testing.T) { + _ = android.GroupFixturePreparers( + java.PrepareForTestWithJavaDefaultModules, + PrepareForTestWithApexBuildComponents, + android.FixtureWithRootAndroidBp(` + platform_bootclasspath { + name: "platform-bootclasspath", + fragments: [ + { + apex: "com.android.art", + module: "art-bootclasspath-fragment", + }, + ], + } + + prebuilt_apex { + name: "com.company.android.art", + apex_name: "com.android.art", + src: "com.company.android.art-arm.apex", + exported_bootclasspath_fragments: ["art-bootclasspath-fragment"], + } + + prebuilt_bootclasspath_fragment { + name: "art-bootclasspath-fragment", + contents: ["core-oj"], + } + + java_import { + name: "core-oj", + jars: ["prebuilt.jar"], + } + `), + ).RunTest(t) +} + +// 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) { + transform := android.NullFixturePreparer + + checkDexJarBuildPath := func(t *testing.T, ctx *android.TestContext, name string) { + // 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() + stem := android.RemoveOptionalPrebuiltPrefix(name) + if expected, actual := ".intermediates/myapex.deapexer/android_common/deapexer/javalib/"+stem+".jar", android.NormalizePathForTesting(dexJarBuildPath); actual != expected { + t.Errorf("Incorrect DexJarBuildPath value '%s', expected '%s'", actual, expected) + } + } + + ensureNoSourceVariant := func(t *testing.T, ctx *android.TestContext, name string) { + // Make sure that an apex variant is not created for the source module. + if expected, actual := []string{"android_common"}, ctx.ModuleVariantsForTests(name); !reflect.DeepEqual(expected, actual) { + t.Errorf("invalid set of variants for %q: expected %q, found %q", "libfoo", expected, actual) + } + } + + t.Run("prebuilt only", func(t *testing.T) { + bp := ` + prebuilt_apex { + name: "myapex", + arch: { + arm64: { + src: "myapex-arm64.apex", + }, + arm: { + src: "myapex-arm.apex", + }, + }, + exported_java_libs: ["libfoo", "libbar"], + } + + java_import { + name: "libfoo", + jars: ["libfoo.jar"], + } + + java_sdk_library_import { + name: "libbar", + public: { + jars: ["libbar.jar"], + }, + } + ` + + // Make sure that dexpreopt can access dex implementation files from the prebuilt. + ctx := testDexpreoptWithApexes(t, bp, "", transform) + + // Make sure that the deapexer has the correct input APEX. + deapexer := ctx.ModuleForTests("myapex.deapexer", "android_common") + rule := deapexer.Rule("deapexer") + if expected, actual := []string{"myapex-arm64.apex"}, android.NormalizePathsForTesting(rule.Implicits); !reflect.DeepEqual(expected, actual) { + t.Errorf("expected: %q, found: %q", expected, actual) + } + + // Make sure that the prebuilt_apex has the correct input APEX. + prebuiltApex := ctx.ModuleForTests("myapex", "android_common_myapex") + rule = prebuiltApex.Rule("android/soong/android.Cp") + if expected, actual := "myapex-arm64.apex", android.NormalizePathForTesting(rule.Input); !reflect.DeepEqual(expected, actual) { + t.Errorf("expected: %q, found: %q", expected, actual) + } + + checkDexJarBuildPath(t, ctx, "libfoo") + + checkDexJarBuildPath(t, ctx, "libbar") + }) + + t.Run("prebuilt with source preferred", func(t *testing.T) { + + bp := ` + prebuilt_apex { + name: "myapex", + arch: { + arm64: { + src: "myapex-arm64.apex", + }, + arm: { + src: "myapex-arm.apex", + }, + }, + exported_java_libs: ["libfoo", "libbar"], + } + + java_import { + name: "libfoo", + jars: ["libfoo.jar"], + } + + java_library { + name: "libfoo", + } + + java_sdk_library_import { + name: "libbar", + public: { + jars: ["libbar.jar"], + }, + } + + java_sdk_library { + name: "libbar", + srcs: ["foo/bar/MyClass.java"], + unsafe_ignore_missing_latest_api: true, + } + ` + + // Make sure that dexpreopt can access dex implementation files from the prebuilt. + ctx := testDexpreoptWithApexes(t, bp, "", transform) + + checkDexJarBuildPath(t, ctx, "prebuilt_libfoo") + ensureNoSourceVariant(t, ctx, "libfoo") + + checkDexJarBuildPath(t, ctx, "prebuilt_libbar") + ensureNoSourceVariant(t, ctx, "libbar") + }) + + t.Run("prebuilt preferred with source", func(t *testing.T) { + bp := ` + prebuilt_apex { + name: "myapex", + arch: { + arm64: { + src: "myapex-arm64.apex", + }, + arm: { + src: "myapex-arm.apex", + }, + }, + exported_java_libs: ["libfoo", "libbar"], + } + + java_import { + name: "libfoo", + prefer: true, + jars: ["libfoo.jar"], + } + + java_library { + name: "libfoo", + } + + java_sdk_library_import { + name: "libbar", + prefer: true, + public: { + jars: ["libbar.jar"], + }, + } + + java_sdk_library { + name: "libbar", + srcs: ["foo/bar/MyClass.java"], + unsafe_ignore_missing_latest_api: true, + } + ` + + // Make sure that dexpreopt can access dex implementation files from the prebuilt. + ctx := testDexpreoptWithApexes(t, bp, "", transform) + + checkDexJarBuildPath(t, ctx, "prebuilt_libfoo") + ensureNoSourceVariant(t, ctx, "libfoo") + + checkDexJarBuildPath(t, ctx, "prebuilt_libbar") + ensureNoSourceVariant(t, ctx, "libbar") + }) +} + +func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { + preparer := android.GroupFixturePreparers( + java.FixtureConfigureBootJars("myapex:libfoo", "myapex:libbar"), + // Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding + // is disabled. + android.FixtureAddTextFile("frameworks/base/Android.bp", ""), + ) + + checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) { + t.Helper() + s := ctx.ModuleForTests("platform-bootclasspath", "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().BuildDir(), s.AllOutputs())) + } + } + + checkHiddenAPIIndexInputs := func(t *testing.T, ctx *android.TestContext, expectedIntermediateInputs string) { + t.Helper() + platformBootclasspath := ctx.ModuleForTests("platform-bootclasspath", "android_common") + var rule android.TestingBuildParams + + rule = platformBootclasspath.Output("hiddenapi-monolithic/index-from-classes.csv") + java.CheckHiddenAPIRuleInputs(t, "intermediate index", expectedIntermediateInputs, rule) + } + + fragment := java.ApexVariantReference{ + Apex: proptools.StringPtr("myapex"), + Module: proptools.StringPtr("my-bootclasspath-fragment"), + } + + t.Run("prebuilt only", func(t *testing.T) { + bp := ` + prebuilt_apex { + name: "myapex", + arch: { + arm64: { + src: "myapex-arm64.apex", + }, + arm: { + src: "myapex-arm.apex", + }, + }, + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + } + + prebuilt_bootclasspath_fragment { + name: "my-bootclasspath-fragment", + contents: ["libfoo", "libbar"], + apex_available: ["myapex"], + } + + java_import { + name: "libfoo", + jars: ["libfoo.jar"], + apex_available: ["myapex"], + } + + java_sdk_library_import { + name: "libbar", + public: { + jars: ["libbar.jar"], + }, + apex_available: ["myapex"], + shared_library: false, + } + ` + + 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") + + // Verify the correct module jars contribute to the hiddenapi index file. + checkHiddenAPIIndexInputs(t, ctx, ` + out/soong/.intermediates/libbar.stubs/android_common/combined/libbar.stubs.jar + out/soong/.intermediates/libfoo/android_common_myapex/combined/libfoo.jar + `) + }) + + t.Run("apex_set only", func(t *testing.T) { + bp := ` + apex_set { + name: "myapex", + set: "myapex.apks", + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + } + + prebuilt_bootclasspath_fragment { + name: "my-bootclasspath-fragment", + contents: ["libfoo", "libbar"], + apex_available: ["myapex"], + } + + java_import { + name: "libfoo", + jars: ["libfoo.jar"], + apex_available: ["myapex"], + } + + java_sdk_library_import { + name: "libbar", + public: { + jars: ["libbar.jar"], + }, + apex_available: ["myapex"], + shared_library: false, + } + ` + + 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") + + // Verify the correct module jars contribute to the hiddenapi index file. + checkHiddenAPIIndexInputs(t, ctx, ` + out/soong/.intermediates/libbar.stubs/android_common/combined/libbar.stubs.jar + out/soong/.intermediates/libfoo/android_common_myapex/combined/libfoo.jar + `) + }) + + t.Run("prebuilt with source library preferred", func(t *testing.T) { + bp := ` + prebuilt_apex { + name: "myapex", + arch: { + arm64: { + src: "myapex-arm64.apex", + }, + arm: { + src: "myapex-arm.apex", + }, + }, + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + } + + prebuilt_bootclasspath_fragment { + name: "my-bootclasspath-fragment", + contents: ["libfoo", "libbar"], + apex_available: ["myapex"], + } + + java_import { + name: "libfoo", + jars: ["libfoo.jar"], + apex_available: ["myapex"], + } + + java_library { + name: "libfoo", + srcs: ["foo/bar/MyClass.java"], + apex_available: ["myapex"], + } + + java_sdk_library_import { + name: "libbar", + public: { + jars: ["libbar.jar"], + }, + apex_available: ["myapex"], + shared_library: false, + } + + java_sdk_library { + name: "libbar", + srcs: ["foo/bar/MyClass.java"], + unsafe_ignore_missing_latest_api: true, + apex_available: ["myapex"], + } + ` + + // In this test the source (java_library) libfoo is active since the + // prebuilt (java_import) defaults to prefer:false. However the + // prebuilt_apex module always depends on the prebuilt, and so it doesn't + // find the dex boot jar in it. We either need to disable the source libfoo + // or make the prebuilt libfoo preferred. + testDexpreoptWithApexes(t, bp, "module libfoo does not provide a dex boot jar", preparer, fragment) + }) + + t.Run("prebuilt library preferred with source", func(t *testing.T) { + bp := ` + prebuilt_apex { + name: "myapex", + arch: { + arm64: { + src: "myapex-arm64.apex", + }, + arm: { + src: "myapex-arm.apex", + }, + }, + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + } + + prebuilt_bootclasspath_fragment { + name: "my-bootclasspath-fragment", + contents: ["libfoo", "libbar"], + apex_available: ["myapex"], + } + + java_import { + name: "libfoo", + prefer: true, + jars: ["libfoo.jar"], + apex_available: ["myapex"], + } + + java_library { + name: "libfoo", + srcs: ["foo/bar/MyClass.java"], + apex_available: ["myapex"], + } + + java_sdk_library_import { + name: "libbar", + prefer: true, + public: { + jars: ["libbar.jar"], + }, + apex_available: ["myapex"], + shared_library: false, + } + + java_sdk_library { + name: "libbar", + srcs: ["foo/bar/MyClass.java"], + unsafe_ignore_missing_latest_api: true, + apex_available: ["myapex"], + } + ` + + 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") + + // Verify the correct module jars contribute to the hiddenapi index file. + checkHiddenAPIIndexInputs(t, ctx, ` + out/soong/.intermediates/prebuilt_libbar.stubs/android_common/combined/libbar.stubs.jar + out/soong/.intermediates/prebuilt_libfoo/android_common_myapex/combined/libfoo.jar + `) + }) + + t.Run("prebuilt with source apex preferred", func(t *testing.T) { + bp := ` + apex { + name: "myapex", + key: "myapex.key", + java_libs: ["libfoo", "libbar"], + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + prebuilt_apex { + name: "myapex", + arch: { + arm64: { + src: "myapex-arm64.apex", + }, + arm: { + src: "myapex-arm.apex", + }, + }, + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + } + + prebuilt_bootclasspath_fragment { + name: "my-bootclasspath-fragment", + contents: ["libfoo", "libbar"], + apex_available: ["myapex"], + } + + java_import { + name: "libfoo", + jars: ["libfoo.jar"], + apex_available: ["myapex"], + } + + java_library { + name: "libfoo", + srcs: ["foo/bar/MyClass.java"], + apex_available: ["myapex"], + } + + java_sdk_library_import { + name: "libbar", + public: { + jars: ["libbar.jar"], + }, + apex_available: ["myapex"], + shared_library: false, + } + + java_sdk_library { + name: "libbar", + srcs: ["foo/bar/MyClass.java"], + unsafe_ignore_missing_latest_api: true, + apex_available: ["myapex"], + } + ` + + ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment) + checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/libfoo/android_common_apex10000/hiddenapi/libfoo.jar") + checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/libbar/android_common_myapex/hiddenapi/libbar.jar") + + // Verify the correct module jars contribute to the hiddenapi index file. + checkHiddenAPIIndexInputs(t, ctx, ` + out/soong/.intermediates/libbar/android_common_myapex/javac/libbar.jar + out/soong/.intermediates/libfoo/android_common_apex10000/javac/libfoo.jar + `) + }) + + t.Run("prebuilt preferred with source apex disabled", func(t *testing.T) { + bp := ` + apex { + name: "myapex", + enabled: false, + key: "myapex.key", + java_libs: ["libfoo", "libbar"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + prebuilt_apex { + name: "myapex", + arch: { + arm64: { + src: "myapex-arm64.apex", + }, + arm: { + src: "myapex-arm.apex", + }, + }, + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + } + + prebuilt_bootclasspath_fragment { + name: "my-bootclasspath-fragment", + contents: ["libfoo", "libbar"], + apex_available: ["myapex"], + } + + java_import { + name: "libfoo", + prefer: true, + jars: ["libfoo.jar"], + apex_available: ["myapex"], + } + + java_library { + name: "libfoo", + srcs: ["foo/bar/MyClass.java"], + apex_available: ["myapex"], + } + + java_sdk_library_import { + name: "libbar", + prefer: true, + public: { + jars: ["libbar.jar"], + }, + apex_available: ["myapex"], + shared_library: false, + } + + java_sdk_library { + name: "libbar", + srcs: ["foo/bar/MyClass.java"], + unsafe_ignore_missing_latest_api: true, + apex_available: ["myapex"], + } + ` + + 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") + + // Verify the correct module jars contribute to the hiddenapi index file. + checkHiddenAPIIndexInputs(t, ctx, ` + out/soong/.intermediates/prebuilt_libbar.stubs/android_common/combined/libbar.stubs.jar + out/soong/.intermediates/prebuilt_libfoo/android_common_myapex/combined/libfoo.jar + `) + }) +} + func TestApexWithTests(t *testing.T) { - ctx, config := testApex(t, ` + ctx := testApex(t, ` apex_test { name: "myapex", key: "myapex.key", + updatable: false, tests: [ "mytest", "mytests", @@ -3241,14 +4862,38 @@ func TestApexWithTests(t *testing.T) { private_key: "testkey.pem", } + filegroup { + name: "fg", + srcs: [ + "baz", + "bar/baz" + ], + } + cc_test { name: "mytest", gtest: false, srcs: ["mytest.cpp"], relative_install_path: "test", + shared_libs: ["mylib"], system_shared_libs: [], static_executable: true, stl: "none", + data: [":fg"], + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + } + + filegroup { + name: "fg2", + srcs: [ + "testdata/baz" + ], } cc_test { @@ -3264,14 +4909,23 @@ func TestApexWithTests(t *testing.T) { system_shared_libs: [], static_executable: true, stl: "none", + data: [ + ":fg", + ":fg2", + ], } `) apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] - // Ensure that test dep is copied into apex. + // Ensure that test dep (and their transitive dependencies) are copied into apex. ensureContains(t, copyCmds, "image.apex/bin/test/mytest") + ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") + + //Ensure that test data are copied into apex. + ensureContains(t, copyCmds, "image.apex/bin/test/baz") + ensureContains(t, copyCmds, "image.apex/bin/test/bar/baz") // Ensure that test deps built with `test_per_src` are copied into apex. ensureContains(t, copyCmds, "image.apex/bin/test/mytest1") @@ -3279,9 +4933,9 @@ func TestApexWithTests(t *testing.T) { ensureContains(t, copyCmds, "image.apex/bin/test/mytest3") // Ensure the module is correctly translated. - apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) - data := android.AndroidMkDataForTest(t, config, "", apexBundle) - name := apexBundle.BaseModuleName() + bundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + data := android.AndroidMkDataForTest(t, ctx, bundle) + name := bundle.BaseModuleName() prefix := "TARGET_" var builder strings.Builder data.Custom(&builder, name, prefix, "", data) @@ -3293,45 +4947,47 @@ func TestApexWithTests(t *testing.T) { ensureContains(t, androidMk, "LOCAL_MODULE := apex_manifest.pb.myapex\n") ensureContains(t, androidMk, "LOCAL_MODULE := apex_pubkey.myapex\n") ensureContains(t, androidMk, "LOCAL_MODULE := myapex\n") + + flatBundle := ctx.ModuleForTests("myapex", "android_common_myapex_flattened").Module().(*apexBundle) + data = android.AndroidMkDataForTest(t, ctx, flatBundle) + data.Custom(&builder, name, prefix, "", data) + flatAndroidMk := builder.String() + ensureContainsOnce(t, flatAndroidMk, "LOCAL_TEST_DATA := :baz :bar/baz\n") + ensureContainsOnce(t, flatAndroidMk, "LOCAL_TEST_DATA := :testdata/baz\n") } func TestInstallExtraFlattenedApexes(t *testing.T) { - ctx, config := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", + updatable: false, } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } - `, func(fs map[string][]byte, config android.Config) { - config.TestProductVariables.InstallExtraFlattenedApexes = proptools.BoolPtr(true) - }) + `, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.InstallExtraFlattenedApexes = proptools.BoolPtr(true) + }), + ) ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) ensureListContains(t, ab.requiredDeps, "myapex.flattened") - mk := android.AndroidMkDataForTest(t, config, "", ab) + mk := android.AndroidMkDataForTest(t, ctx, ab) var builder strings.Builder mk.Custom(&builder, ab.Name(), "TARGET_", "", mk) androidMk := builder.String() ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += myapex.flattened") } -func TestApexUsesOtherApex(t *testing.T) { - ctx, _ := testApex(t, ` +func TestErrorsIfDepsAreNotEnabled(t *testing.T) { + testApexError(t, `module "myapex" .* depends on disabled module "libfoo"`, ` apex { name: "myapex", key: "myapex.key", - native_shared_libs: ["mylib"], - uses: ["commonapex"], - } - - apex { - name: "commonapex", - key: "myapex.key", - native_shared_libs: ["libcommon"], - provide_cpp_shared_libs: true, + native_shared_libs: ["libfoo"], } apex_key { @@ -3341,54 +4997,18 @@ func TestApexUsesOtherApex(t *testing.T) { } cc_library { - name: "mylib", - srcs: ["mylib.cpp"], - shared_libs: ["libcommon"], - system_shared_libs: [], + name: "libfoo", stl: "none", - apex_available: [ "myapex" ], - } - - cc_library { - name: "libcommon", - srcs: ["mylib_common.cpp"], system_shared_libs: [], - stl: "none", - // TODO: remove //apex_available:platform - apex_available: [ - "//apex_available:platform", - "commonapex", - "myapex", - ], + enabled: false, + apex_available: ["myapex"], } `) - - module1 := ctx.ModuleForTests("myapex", "android_common_myapex_image") - apexRule1 := module1.Rule("apexRule") - copyCmds1 := apexRule1.Args["copy_commands"] - - module2 := ctx.ModuleForTests("commonapex", "android_common_commonapex_image") - apexRule2 := module2.Rule("apexRule") - copyCmds2 := apexRule2.Args["copy_commands"] - - ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex") - ensureListContains(t, ctx.ModuleVariantsForTests("libcommon"), "android_arm64_armv8-a_shared_commonapex") - ensureContains(t, copyCmds1, "image.apex/lib64/mylib.so") - ensureContains(t, copyCmds2, "image.apex/lib64/libcommon.so") - ensureNotContains(t, copyCmds1, "image.apex/lib64/libcommon.so") -} - -func TestApexUsesFailsIfNotProvided(t *testing.T) { - testApexError(t, `uses: "commonapex" does not provide native_shared_libs`, ` + testApexError(t, `module "myapex" .* depends on disabled module "myjar"`, ` apex { name: "myapex", key: "myapex.key", - uses: ["commonapex"], - } - - apex { - name: "commonapex", - key: "myapex.key", + java_libs: ["myjar"], } apex_key { @@ -3396,41 +5016,25 @@ func TestApexUsesFailsIfNotProvided(t *testing.T) { public_key: "testkey.avbpubkey", private_key: "testkey.pem", } - `) - testApexError(t, `uses: "commonapex" is not a provider`, ` - apex { - name: "myapex", - key: "myapex.key", - uses: ["commonapex"], - } - cc_library { - name: "commonapex", - system_shared_libs: [], - stl: "none", - } - - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", + java_library { + name: "myjar", + srcs: ["foo/bar/MyClass.java"], + sdk_version: "none", + system_modules: "none", + enabled: false, + apex_available: ["myapex"], } `) } -func TestApexUsesFailsIfUseVenderMismatch(t *testing.T) { - testApexError(t, `use_vendor: "commonapex" has different value of use_vendor`, ` +func TestApexWithJavaImport(t *testing.T) { + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", - use_vendor: true, - uses: ["commonapex"], - } - - apex { - name: "commonapex", - key: "myapex.key", - provide_cpp_shared_libs: true, + java_libs: ["myjavaimport"], + updatable: false, } apex_key { @@ -3438,59 +5042,23 @@ func TestApexUsesFailsIfUseVenderMismatch(t *testing.T) { public_key: "testkey.avbpubkey", private_key: "testkey.pem", } - `, func(fs map[string][]byte, config android.Config) { - setUseVendorAllowListForTest(config, []string{"myapex"}) - }) -} -func TestErrorsIfDepsAreNotEnabled(t *testing.T) { - testApexError(t, `module "myapex" .* depends on disabled module "libfoo"`, ` - apex { - name: "myapex", - key: "myapex.key", - native_shared_libs: ["libfoo"], - } - - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } - - cc_library { - name: "libfoo", - stl: "none", - system_shared_libs: [], - enabled: false, + java_import { + name: "myjavaimport", apex_available: ["myapex"], + jars: ["my.jar"], + compile_dex: true, } `) - testApexError(t, `module "myapex" .* depends on disabled module "myjar"`, ` - apex { - name: "myapex", - key: "myapex.key", - java_libs: ["myjar"], - } - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } - - java_library { - name: "myjar", - srcs: ["foo/bar/MyClass.java"], - sdk_version: "none", - system_modules: "none", - enabled: false, - apex_available: ["myapex"], - } - `) + module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + apexRule := module.Rule("apexRule") + copyCmds := apexRule.Args["copy_commands"] + ensureContains(t, copyCmds, "image.apex/javalib/myjavaimport.jar") } func TestApexWithApps(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", @@ -3498,6 +5066,7 @@ func TestApexWithApps(t *testing.T) { "AppFoo", "AppFooPriv", ], + updatable: false, } apex_key { @@ -3552,14 +5121,14 @@ func TestApexWithApps(t *testing.T) { ensureContains(t, copyCmds, "image.apex/app/AppFoo/AppFoo.apk") ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPriv/AppFooPriv.apk") - appZipRule := ctx.ModuleForTests("AppFoo", "android_common_myapex").Description("zip jni libs") + appZipRule := ctx.ModuleForTests("AppFoo", "android_common_apex10000").Description("zip jni libs") // JNI libraries are uncompressed if args := appZipRule.Args["jarArgs"]; !strings.Contains(args, "-L 0") { t.Errorf("jni libs are not uncompressed for AppFoo") } // JNI libraries including transitive deps are for _, jni := range []string{"libjni", "libfoo"} { - jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_myapex").Module().(*cc.Module).OutputFile() + jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_apex10000").Module().(*cc.Module).OutputFile().RelativeToTop() // ... embedded inside APK (jnilibs.zip) ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String()) // ... and not directly inside the APEX @@ -3568,7 +5137,7 @@ func TestApexWithApps(t *testing.T) { } func TestApexWithAppImports(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", @@ -3576,6 +5145,7 @@ func TestApexWithAppImports(t *testing.T) { "AppFooPrebuilt", "AppFooPrivPrebuilt", ], + updatable: false, } apex_key { @@ -3591,6 +5161,7 @@ func TestApexWithAppImports(t *testing.T) { dex_preopt: { enabled: false, }, + apex_available: ["myapex"], } android_app_import { @@ -3602,6 +5173,7 @@ func TestApexWithAppImports(t *testing.T) { enabled: false, }, filename: "AwesomePrebuiltAppFooPriv.apk", + apex_available: ["myapex"], } `) @@ -3614,13 +5186,14 @@ func TestApexWithAppImports(t *testing.T) { } func TestApexWithAppImportsPrefer(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", apps: [ "AppFoo", ], + updatable: false, } apex_key { @@ -3643,6 +5216,7 @@ func TestApexWithAppImportsPrefer(t *testing.T) { filename: "AppFooPrebuilt.apk", presigned: true, prefer: true, + apex_available: ["myapex"], } `, withFiles(map[string][]byte{ "AppFooPrebuilt.apk": nil, @@ -3654,13 +5228,14 @@ func TestApexWithAppImportsPrefer(t *testing.T) { } func TestApexWithTestHelperApp(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", apps: [ "TesterHelpAppFoo", ], + updatable: false, } apex_key { @@ -3686,11 +5261,12 @@ func TestApexWithTestHelperApp(t *testing.T) { func TestApexPropertiesShouldBeDefaultable(t *testing.T) { // libfoo's apex_available comes from cc_defaults - testApexError(t, `requires "libfoo" that is not available for the APEX`, ` + testApexError(t, `requires "libfoo" that doesn't list the APEX under 'apex_available'.`, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["libfoo"], + updatable: false, } apex_key { @@ -3703,6 +5279,7 @@ func TestApexPropertiesShouldBeDefaultable(t *testing.T) { name: "otherapex", key: "myapex.key", native_shared_libs: ["libfoo"], + updatable: false, } cc_defaults { @@ -3720,11 +5297,12 @@ func TestApexPropertiesShouldBeDefaultable(t *testing.T) { func TestApexAvailable_DirectDep(t *testing.T) { // libfoo is not available to myapex, but only to otherapex - testApexError(t, "requires \"libfoo\" that is not available for the APEX", ` + testApexError(t, "requires \"libfoo\" that doesn't list the APEX under 'apex_available'.", ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["libfoo"], + updatable: false, } apex_key { @@ -3737,6 +5315,7 @@ func TestApexAvailable_DirectDep(t *testing.T) { name: "otherapex", key: "otherapex.key", native_shared_libs: ["libfoo"], + updatable: false, } apex_key { @@ -3755,17 +5334,18 @@ func TestApexAvailable_DirectDep(t *testing.T) { func TestApexAvailable_IndirectDep(t *testing.T) { // libbbaz is an indirect dep - testApexError(t, `requires "libbaz" that is not available for the APEX. Dependency path: -.*via tag apex\.dependencyTag.*"sharedLib".* + testApexError(t, `requires "libbaz" that doesn't list the APEX under 'apex_available'.\n\nDependency path: +.*via tag apex\.dependencyTag.*name:sharedLib.* .*-> libfoo.*link:shared.* -.*via tag cc\.DependencyTag.*"shared".* +.*via tag cc\.libraryDependencyTag.*Kind:sharedLibraryDependency.* .*-> libbar.*link:shared.* -.*via tag cc\.DependencyTag.*"shared".* +.*via tag cc\.libraryDependencyTag.*Kind:sharedLibraryDependency.* .*-> libbaz.*link:shared.*`, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["libfoo"], + updatable: false, } apex_key { @@ -3803,6 +5383,7 @@ func TestApexAvailable_InvalidApexName(t *testing.T) { name: "myapex", key: "myapex.key", native_shared_libs: ["libfoo"], + updatable: false, } apex_key { @@ -3823,6 +5404,7 @@ func TestApexAvailable_InvalidApexName(t *testing.T) { name: "myapex", key: "myapex.key", native_shared_libs: ["libfoo", "libbar"], + updatable: false, } apex_key { @@ -3857,11 +5439,12 @@ func TestApexAvailable_InvalidApexName(t *testing.T) { } func TestApexAvailable_CheckForPlatform(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["libbar", "libbaz"], + updatable: false, } apex_key { @@ -3919,11 +5502,12 @@ func TestApexAvailable_CheckForPlatform(t *testing.T) { } func TestApexAvailable_CreatedForApex(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["libfoo"], + updatable: false, } apex_key { @@ -3953,12 +5537,13 @@ func TestApexAvailable_CreatedForApex(t *testing.T) { } func TestOverrideApex(t *testing.T) { - ctx, config := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", apps: ["app"], overrides: ["oldapex"], + updatable: false, } override_apex { @@ -3968,6 +5553,8 @@ func TestOverrideApex(t *testing.T) { overrides: ["unknownapex"], logging_parent: "com.foo.bar", package_name: "test.overridden.package", + key: "mynewapex.key", + certificate: ":myapex.certificate", } apex_key { @@ -3976,6 +5563,17 @@ func TestOverrideApex(t *testing.T) { private_key: "testkey.pem", } + apex_key { + name: "mynewapex.key", + public_key: "testkey2.avbpubkey", + private_key: "testkey2.pem", + } + + android_app_certificate { + name: "myapex.certificate", + certificate: "testkey", + } + android_app { name: "app", srcs: ["foo/bar/MyClass.java"], @@ -4020,8 +5618,12 @@ func TestOverrideApex(t *testing.T) { optFlags := apexRule.Args["opt_flags"] ensureContains(t, optFlags, "--override_apk_package_name test.overridden.package") + ensureContains(t, optFlags, "--pubkey testkey2.avbpubkey") - data := android.AndroidMkDataForTest(t, config, "", apexBundle) + signApkRule := module.Rule("signapk") + ensureEquals(t, signApkRule.Args["certificates"], "testkey.x509.pem testkey.pk8") + + data := android.AndroidMkDataForTest(t, ctx, apexBundle) var builder strings.Builder data.Custom(&builder, name, "TARGET_", "", data) androidMk := builder.String() @@ -4036,7 +5638,7 @@ func TestOverrideApex(t *testing.T) { } func TestLegacyAndroid10Support(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", @@ -4056,6 +5658,7 @@ func TestLegacyAndroid10Support(t *testing.T) { stl: "libc++", system_shared_libs: [], apex_available: [ "myapex" ], + min_sdk_version: "29", } `, withUnbundledBuild) @@ -4069,7 +5672,7 @@ func TestLegacyAndroid10Support(t *testing.T) { // the dependency names directly here but for some reason the names are blank in // this test. for _, lib := range []string{"libc++", "mylib"} { - apexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared_myapex").Rule("ld").Implicits + apexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared_apex29").Rule("ld").Implicits nonApexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld").Implicits if len(apexImplicits) != len(nonApexImplicits)+1 { t.Errorf("%q missing unwinder dep", lib) @@ -4077,7 +5680,7 @@ func TestLegacyAndroid10Support(t *testing.T) { } } -var filesForSdkLibrary = map[string][]byte{ +var filesForSdkLibrary = android.MockFS{ "api/current.txt": nil, "api/removed.txt": nil, "api/system-current.txt": nil, @@ -4085,16 +5688,22 @@ var filesForSdkLibrary = map[string][]byte{ "api/test-current.txt": nil, "api/test-removed.txt": nil, + "100/public/api/foo.txt": nil, + "100/public/api/foo-removed.txt": nil, + "100/system/api/foo.txt": nil, + "100/system/api/foo-removed.txt": nil, + // For java_sdk_library_import "a.jar": nil, } func TestJavaSDKLibrary(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", java_libs: ["foo"], + updatable: false, } apex_key { @@ -4109,6 +5718,11 @@ func TestJavaSDKLibrary(t *testing.T) { api_packages: ["foo"], apex_available: [ "myapex" ], } + + prebuilt_apis { + name: "sdk", + api_dirs: ["100"], + } `, withFiles(filesForSdkLibrary)) // java_sdk_library installs both impl jar and permission XML @@ -4122,11 +5736,12 @@ func TestJavaSDKLibrary(t *testing.T) { } func TestJavaSDKLibrary_WithinApex(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", java_libs: ["foo", "bar"], + updatable: false, } apex_key { @@ -4152,6 +5767,11 @@ func TestJavaSDKLibrary_WithinApex(t *testing.T) { sdk_version: "none", system_modules: "none", } + + prebuilt_apis { + name: "sdk", + api_dirs: ["100"], + } `, withFiles(filesForSdkLibrary)) // java_sdk_library installs both impl jar and permission XML @@ -4163,17 +5783,18 @@ func TestJavaSDKLibrary_WithinApex(t *testing.T) { // The bar library should depend on the implementation jar. barLibrary := ctx.ModuleForTests("bar", "android_common_myapex").Rule("javac") - if expected, actual := `^-classpath /[^:]*/turbine-combined/foo\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { + if expected, actual := `^-classpath [^:]*/turbine-combined/foo\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { t.Errorf("expected %q, found %#q", expected, actual) } } func TestJavaSDKLibrary_CrossBoundary(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", java_libs: ["foo"], + updatable: false, } apex_key { @@ -4198,6 +5819,11 @@ func TestJavaSDKLibrary_CrossBoundary(t *testing.T) { sdk_version: "none", system_modules: "none", } + + prebuilt_apis { + name: "sdk", + api_dirs: ["100"], + } `, withFiles(filesForSdkLibrary)) // java_sdk_library installs both impl jar and permission XML @@ -4208,13 +5834,17 @@ func TestJavaSDKLibrary_CrossBoundary(t *testing.T) { // The bar library should depend on the stubs jar. barLibrary := ctx.ModuleForTests("bar", "android_common").Rule("javac") - if expected, actual := `^-classpath /[^:]*/turbine-combined/foo\.stubs\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { + if expected, actual := `^-classpath [^:]*/turbine-combined/foo\.stubs\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { t.Errorf("expected %q, found %#q", expected, actual) } } func TestJavaSDKLibrary_ImportPreferred(t *testing.T) { - ctx, _ := testApex(t, ``, + ctx := testApex(t, ` + prebuilt_apis { + name: "sdk", + api_dirs: ["100"], + }`, withFiles(map[string][]byte{ "apex/a.java": nil, "apex/apex_manifest.json": nil, @@ -4227,6 +5857,7 @@ func TestJavaSDKLibrary_ImportPreferred(t *testing.T) { name: "myapex", key: "myapex.key", java_libs: ["foo", "bar"], + updatable: false, } apex_key { @@ -4281,7 +5912,7 @@ func TestJavaSDKLibrary_ImportPreferred(t *testing.T) { }, } `), - }), + }), withFiles(filesForSdkLibrary), ) // java_sdk_library installs both impl jar and permission XML @@ -4293,7 +5924,7 @@ func TestJavaSDKLibrary_ImportPreferred(t *testing.T) { // The bar library should depend on the implementation jar. barLibrary := ctx.ModuleForTests("bar", "android_common_myapex").Rule("javac") - if expected, actual := `^-classpath /[^:]*/turbine-combined/foo\.impl\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { + if expected, actual := `^-classpath [^:]*/turbine-combined/foo\.impl\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { t.Errorf("expected %q, found %#q", expected, actual) } } @@ -4304,6 +5935,7 @@ func TestJavaSDKLibrary_ImportOnly(t *testing.T) { name: "myapex", key: "myapex.key", java_libs: ["foo"], + updatable: false, } apex_key { @@ -4325,12 +5957,16 @@ func TestJavaSDKLibrary_ImportOnly(t *testing.T) { } func TestCompatConfig(t *testing.T) { - ctx, _ := testApex(t, ` + result := android.GroupFixturePreparers( + prepareForApexTest, + java.PrepareForTestWithPlatformCompatConfig, + ).RunTestWithBp(t, ` apex { name: "myapex", key: "myapex.key", - prebuilts: ["myjar-platform-compat-config"], + compat_configs: ["myjar-platform-compat-config"], java_libs: ["myjar"], + updatable: false, } apex_key { @@ -4351,7 +5987,15 @@ func TestCompatConfig(t *testing.T) { system_modules: "none", apex_available: [ "myapex" ], } + + // Make sure that a preferred prebuilt does not affect the apex contents. + prebuilt_platform_compat_config { + name: "myjar-platform-compat-config", + metadata: "compat-config/metadata.xml", + prefer: true, + } `) + ctx := result.TestContext ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ "etc/compatconfig/myjar-platform-compat-config.xml", "javalib/myjar.jar", @@ -4364,6 +6008,7 @@ func TestRejectNonInstallableJavaLibrary(t *testing.T) { name: "myapex", key: "myapex.key", java_libs: ["myjar"], + updatable: false, } apex_key { @@ -4384,11 +6029,12 @@ func TestRejectNonInstallableJavaLibrary(t *testing.T) { } func TestCarryRequiredModuleNames(t *testing.T) { - ctx, config := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], + updatable: false, } apex_key { @@ -4410,7 +6056,7 @@ func TestCarryRequiredModuleNames(t *testing.T) { `) apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) - data := android.AndroidMkDataForTest(t, config, "", apexBundle) + data := android.AndroidMkDataForTest(t, ctx, apexBundle) name := apexBundle.BaseModuleName() prefix := "TARGET_" var builder strings.Builder @@ -4428,6 +6074,7 @@ func TestSymlinksFromApexToSystem(t *testing.T) { key: "myapex.key", native_shared_libs: ["mylib"], java_libs: ["myjar"], + updatable: false, } apex { @@ -4456,6 +6103,7 @@ func TestSymlinksFromApexToSystem(t *testing.T) { "myapex.updatable", "//apex_available:platform", ], + min_sdk_version: "current", } cc_library { @@ -4468,6 +6116,7 @@ func TestSymlinksFromApexToSystem(t *testing.T) { "myapex.updatable", "//apex_available:platform", ], + min_sdk_version: "current", } java_library { @@ -4481,6 +6130,7 @@ func TestSymlinksFromApexToSystem(t *testing.T) { "myapex.updatable", "//apex_available:platform", ], + min_sdk_version: "current", } java_library { @@ -4493,6 +6143,7 @@ func TestSymlinksFromApexToSystem(t *testing.T) { "myapex.updatable", "//apex_available:platform", ], + min_sdk_version: "current", } ` @@ -4522,7 +6173,7 @@ func TestSymlinksFromApexToSystem(t *testing.T) { // For unbundled build, symlink shouldn't exist regardless of whether an APEX // is updatable or not - ctx, _ := testApex(t, bp, withUnbundledBuild) + ctx := testApex(t, bp, withUnbundledBuild) files := getFiles(t, ctx, "myapex", "android_common_myapex_image") ensureRealfileExists(t, files, "javalib/myjar.jar") ensureRealfileExists(t, files, "lib64/mylib.so") @@ -4534,7 +6185,7 @@ func TestSymlinksFromApexToSystem(t *testing.T) { ensureRealfileExists(t, files, "lib64/myotherlib.so") // For bundled build, symlink to the system for the non-updatable APEXes only - ctx, _ = testApex(t, bp) + ctx = testApex(t, bp) files = getFiles(t, ctx, "myapex", "android_common_myapex_image") ensureRealfileExists(t, files, "javalib/myjar.jar") ensureRealfileExists(t, files, "lib64/mylib.so") @@ -4546,21 +6197,118 @@ func TestSymlinksFromApexToSystem(t *testing.T) { ensureRealfileExists(t, files, "lib64/myotherlib.so") // this is a real file } -func TestApexMutatorsDontRunIfDisabled(t *testing.T) { - ctx, _ := testApex(t, ` +func TestSymlinksFromApexToSystemRequiredModuleNames(t *testing.T) { + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", + native_shared_libs: ["mylib"], + updatable: false, } + apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } - `, func(fs map[string][]byte, config android.Config) { - delete(config.Targets, android.Android) - config.AndroidCommonTarget = android.Target{} + + cc_library_shared { + name: "mylib", + srcs: ["mylib.cpp"], + shared_libs: ["myotherlib"], + system_shared_libs: [], + stl: "none", + apex_available: [ + "myapex", + "//apex_available:platform", + ], + } + + cc_prebuilt_library_shared { + name: "myotherlib", + srcs: ["prebuilt.so"], + system_shared_libs: [], + stl: "none", + apex_available: [ + "myapex", + "//apex_available:platform", + ], + } + `) + + apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + data := android.AndroidMkDataForTest(t, ctx, apexBundle) + var builder strings.Builder + data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data) + androidMk := builder.String() + // `myotherlib` is added to `myapex` as symlink + ensureContains(t, androidMk, "LOCAL_MODULE := mylib.myapex\n") + ensureNotContains(t, androidMk, "LOCAL_MODULE := prebuilt_myotherlib.myapex\n") + ensureNotContains(t, androidMk, "LOCAL_MODULE := myotherlib.myapex\n") + // `myapex` should have `myotherlib` in its required line, not `prebuilt_myotherlib` + ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += mylib.myapex:64 myotherlib:64 apex_manifest.pb.myapex apex_pubkey.myapex\n") +} + +func TestApexWithJniLibs(t *testing.T) { + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + jni_libs: ["mylib"], + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + shared_libs: ["mylib2"], + system_shared_libs: [], + stl: "none", + apex_available: [ "myapex" ], + } + + cc_library { + name: "mylib2", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: [ "myapex" ], + } + `) + + rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") + // Notice mylib2.so (transitive dep) is not added as a jni_lib + ensureEquals(t, rule.Args["opt"], "-a jniLibs mylib.so") + ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + "lib64/mylib.so", + "lib64/mylib2.so", }) +} + +func TestApexMutatorsDontRunIfDisabled(t *testing.T) { + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + updatable: false, + } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + `, + android.FixtureModifyConfig(func(config android.Config) { + delete(config.Targets, android.Android) + config.AndroidCommonTarget = android.Target{} + }), + ) if expected, got := []string{""}, ctx.ModuleVariantsForTests("myapex"); !reflect.DeepEqual(expected, got) { t.Errorf("Expected variants: %v, but got: %v", expected, got) @@ -4568,11 +6316,12 @@ func TestApexMutatorsDontRunIfDisabled(t *testing.T) { } func TestAppBundle(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", apps: ["AppFoo"], + updatable: false, } apex_key { @@ -4590,7 +6339,7 @@ func TestAppBundle(t *testing.T) { } `, withManifestPackageNameOverrides([]string{"AppFoo:com.android.foo"})) - bundleConfigRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Description("Bundle Config") + bundleConfigRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("bundle_config.json") content := bundleConfigRule.Args["content"] ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`) @@ -4598,11 +6347,12 @@ func TestAppBundle(t *testing.T) { } func TestAppSetBundle(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", apps: ["AppSet"], + updatable: false, } apex_key { @@ -4616,7 +6366,7 @@ func TestAppSetBundle(t *testing.T) { set: "AppSet.apks", }`) mod := ctx.ModuleForTests("myapex", "android_common_myapex_image") - bundleConfigRule := mod.Description("Bundle Config") + bundleConfigRule := mod.Output("bundle_config.json") content := bundleConfigRule.Args["content"] ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`) s := mod.Rule("apexRule").Args["copy_commands"] @@ -4629,96 +6379,37 @@ func TestAppSetBundle(t *testing.T) { ensureMatches(t, copyCmds[2], "^unzip .*-d .*/app/AppSet .*/AppSet.zip$") } -func testNoUpdatableJarsInBootImage(t *testing.T, errmsg, bp string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) { - t.Helper() - - bp = bp + ` - filegroup { - name: "some-updatable-apex-file_contexts", - srcs: [ - "system/sepolicy/apex/some-updatable-apex-file_contexts", - ], - } - - filegroup { - name: "some-non-updatable-apex-file_contexts", - srcs: [ - "system/sepolicy/apex/some-non-updatable-apex-file_contexts", - ], +func TestAppSetBundlePrebuilt(t *testing.T) { + bp := ` + apex_set { + name: "myapex", + filename: "foo_v2.apex", + sanitized: { + none: { set: "myapex.apks", }, + hwaddress: { set: "myapex.hwasan.apks", }, + }, } ` - bp += cc.GatherRequiredDepsForTest(android.Android) - bp += java.GatherRequiredDepsForTest() - bp += dexpreopt.BpToolModulesForTest() - - fs := map[string][]byte{ - "a.java": nil, - "a.jar": nil, - "build/make/target/product/security": nil, - "apex_manifest.json": nil, - "AndroidManifest.xml": nil, - "system/sepolicy/apex/some-updatable-apex-file_contexts": nil, - "system/sepolicy/apex/some-non-updatable-apex-file_contexts": nil, - "system/sepolicy/apex/com.android.art.something-file_contexts": nil, - "framework/aidl/a.aidl": nil, - } - cc.GatherRequiredFilesForTest(fs) - - ctx := android.NewTestArchContext() - ctx.RegisterModuleType("apex", BundleFactory) - ctx.RegisterModuleType("apex_key", ApexKeyFactory) - ctx.RegisterModuleType("filegroup", android.FileGroupFactory) - ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) - cc.RegisterRequiredBuildComponentsForTest(ctx) - java.RegisterJavaBuildComponents(ctx) - java.RegisterSystemModulesBuildComponents(ctx) - java.RegisterAppBuildComponents(ctx) - java.RegisterDexpreoptBootJarsComponents(ctx) - ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators) - ctx.PreDepsMutators(RegisterPreDepsMutators) - ctx.PostDepsMutators(RegisterPostDepsMutators) - - config := android.TestArchConfig(buildDir, nil, bp, fs) - ctx.Register(config) - - _ = dexpreopt.GlobalSoongConfigForTests(config) - dexpreopt.RegisterToolModulesForTest(ctx) - pathCtx := android.PathContextForTesting(config) - dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx) - transformDexpreoptConfig(dexpreoptConfig) - dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig) - - _, errs := ctx.ParseBlueprintsFiles("Android.bp") - android.FailIfErrored(t, errs) - - _, errs = ctx.PrepareBuildActions(config) - if errmsg == "" { - android.FailIfErrored(t, errs) - } else if len(errs) > 0 { - android.FailIfNoMatchingErrors(t, errmsg, errs) - return - } else { - t.Fatalf("missing expected error %q (0 errors are returned)", errmsg) - } -} + ctx := testApex(t, bp, prepareForTestWithSantitizeHwaddress) -func TestUpdatable_should_set_min_sdk_version(t *testing.T) { - testApexError(t, `"myapex" .*: updatable: updatable APEXes should set min_sdk_version`, ` - apex { - name: "myapex", - key: "myapex.key", - updatable: true, - } + // 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" - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } - `) + m := ctx.ModuleForTests("myapex.apex.extractor", "android_common") + extractedApex := m.Output(extractorOutput) + + android.AssertArrayString(t, "extractor input", []string{"myapex.hwasan.apks"}, extractedApex.Inputs.Strings()) + + // Ditto for the apex. + m = ctx.ModuleForTests("myapex", "android_common_myapex") + copiedApex := m.Output("out/soong/.intermediates/myapex/android_common_myapex/foo_v2.apex") + + android.AssertStringEquals(t, "myapex input", extractorOutput, copiedApex.Input.String()) } -func TestNoUpdatableJarsInBootImage(t *testing.T) { +func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, preparer android.FixturePreparer, fragments ...java.ApexVariantReference) { + t.Helper() + bp := ` java_library { name: "some-updatable-apex-lib", @@ -4735,6 +6426,15 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { apex_available: [ "some-non-updatable-apex", ], + compile_dex: true, + } + + bootclasspath_fragment { + name: "some-non-updatable-fragment", + contents: ["some-non-updatable-apex-lib"], + apex_available: [ + "some-non-updatable-apex", + ], } java_library { @@ -4749,9 +6449,10 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { srcs: ["a.java"], sdk_version: "current", apex_available: [ - "com.android.art.something", + "com.android.art.debug", ], hostdex: true, + compile_dex: true, } apex { @@ -4765,7 +6466,8 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { apex { name: "some-non-updatable-apex", key: "some-non-updatable-apex.key", - java_libs: ["some-non-updatable-apex-lib"], + bootclasspath_fragments: ["some-non-updatable-fragment"], + updatable: false, } apex_key { @@ -4777,139 +6479,361 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { } apex { - name: "com.android.art.something", - key: "com.android.art.something.key", - java_libs: ["some-art-lib"], + name: "com.android.art.debug", + key: "com.android.art.debug.key", + bootclasspath_fragments: ["art-bootclasspath-fragment"], updatable: true, min_sdk_version: "current", } + bootclasspath_fragment { + name: "art-bootclasspath-fragment", + image_name: "art", + contents: ["some-art-lib"], + apex_available: [ + "com.android.art.debug", + ], + } + apex_key { - name: "com.android.art.something.key", + name: "com.android.art.debug.key", + } + + filegroup { + name: "some-updatable-apex-file_contexts", + srcs: [ + "system/sepolicy/apex/some-updatable-apex-file_contexts", + ], + } + + filegroup { + name: "some-non-updatable-apex-file_contexts", + srcs: [ + "system/sepolicy/apex/some-non-updatable-apex-file_contexts", + ], } ` - var error string - var transform func(*dexpreopt.GlobalConfig) + testDexpreoptWithApexes(t, bp, errmsg, preparer, fragments...) +} - // updatable jar from ART apex in the ART boot image => ok - transform = func(config *dexpreopt.GlobalConfig) { - config.ArtApexJars = []string{"some-art-lib"} - } - testNoUpdatableJarsInBootImage(t, "", bp, transform) +func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.FixturePreparer, fragments ...java.ApexVariantReference) *android.TestContext { + t.Helper() - // updatable jar from ART apex in the framework boot image => error - error = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image" - transform = func(config *dexpreopt.GlobalConfig) { - config.BootJars = []string{"some-art-lib"} - } - testNoUpdatableJarsInBootImage(t, error, bp, transform) + fs := android.MockFS{ + "a.java": nil, + "a.jar": nil, + "apex_manifest.json": nil, + "AndroidManifest.xml": nil, + "system/sepolicy/apex/myapex-file_contexts": nil, + "system/sepolicy/apex/some-updatable-apex-file_contexts": nil, + "system/sepolicy/apex/some-non-updatable-apex-file_contexts": nil, + "system/sepolicy/apex/com.android.art.debug-file_contexts": nil, + "framework/aidl/a.aidl": nil, + } + + errorHandler := android.FixtureExpectsNoErrors + if errmsg != "" { + errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(errmsg) + } + + result := android.GroupFixturePreparers( + cc.PrepareForTestWithCcDefaultModules, + java.PrepareForTestWithHiddenApiBuildComponents, + java.PrepareForTestWithJavaDefaultModules, + java.PrepareForTestWithJavaSdkLibraryFiles, + PrepareForTestWithApexBuildComponents, + preparer, + fs.AddToFixture(), + android.FixtureModifyMockFS(func(fs android.MockFS) { + if _, ok := fs["frameworks/base/boot/Android.bp"]; !ok { + insert := "" + for _, fragment := range fragments { + insert += fmt.Sprintf("{apex: %q, module: %q},\n", *fragment.Apex, *fragment.Module) + } + fs["frameworks/base/boot/Android.bp"] = []byte(fmt.Sprintf(` + platform_bootclasspath { + name: "platform-bootclasspath", + fragments: [ + %s + ], + } + `, insert)) + } + }), + ). + ExtendWithErrorHandler(errorHandler). + RunTestWithBp(t, bp) - // updatable jar from some other apex in the ART boot image => error - error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image" - transform = func(config *dexpreopt.GlobalConfig) { - config.ArtApexJars = []string{"some-updatable-apex-lib"} - } - testNoUpdatableJarsInBootImage(t, error, bp, transform) + return result.TestContext +} - // non-updatable jar from some other apex in the ART boot image => error - error = "module 'some-non-updatable-apex-lib' is not allowed in the ART boot image" - transform = func(config *dexpreopt.GlobalConfig) { - config.ArtApexJars = []string{"some-non-updatable-apex-lib"} - } - testNoUpdatableJarsInBootImage(t, error, bp, transform) +func TestDuplicateDeapexeresFromPrebuiltApexes(t *testing.T) { + preparers := android.GroupFixturePreparers( + java.PrepareForTestWithJavaDefaultModules, + PrepareForTestWithApexBuildComponents, + ). + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( + `Ambiguous duplicate deapexer module dependencies "com.android.myapex.deapexer" and "com.mycompany.android.myapex.deapexer"`)) - // updatable jar from some other apex in the framework boot image => error - error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image" - transform = func(config *dexpreopt.GlobalConfig) { - config.BootJars = []string{"some-updatable-apex-lib"} - } - testNoUpdatableJarsInBootImage(t, error, bp, transform) + bpBase := ` + apex_set { + name: "com.android.myapex", + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + set: "myapex.apks", + } - // non-updatable jar from some other apex in the framework boot image => ok - transform = func(config *dexpreopt.GlobalConfig) { - config.BootJars = []string{"some-non-updatable-apex-lib"} - } - testNoUpdatableJarsInBootImage(t, "", bp, transform) + apex_set { + name: "com.mycompany.android.myapex", + apex_name: "com.android.myapex", + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + set: "company-myapex.apks", + } - // nonexistent jar in the ART boot image => error - error = "failed to find a dex jar path for module 'nonexistent'" - transform = func(config *dexpreopt.GlobalConfig) { - config.ArtApexJars = []string{"nonexistent"} - } - testNoUpdatableJarsInBootImage(t, error, bp, transform) + prebuilt_bootclasspath_fragment { + name: "my-bootclasspath-fragment", + apex_available: ["com.android.myapex"], + %s + } + ` - // nonexistent jar in the framework boot image => error - error = "failed to find a dex jar path for module 'nonexistent'" - transform = func(config *dexpreopt.GlobalConfig) { - config.BootJars = []string{"nonexistent"} - } - testNoUpdatableJarsInBootImage(t, error, bp, transform) + t.Run("java_import", func(t *testing.T) { + _ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+` + java_import { + name: "libfoo", + jars: ["libfoo.jar"], + apex_available: ["com.android.myapex"], + } + `) + }) - // platform jar in the ART boot image => error - error = "module 'some-platform-lib' is not allowed in the ART boot image" - transform = func(config *dexpreopt.GlobalConfig) { - config.ArtApexJars = []string{"some-platform-lib"} - } - testNoUpdatableJarsInBootImage(t, error, bp, transform) + t.Run("java_sdk_library_import", func(t *testing.T) { + _ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+` + java_sdk_library_import { + name: "libfoo", + public: { + jars: ["libbar.jar"], + }, + apex_available: ["com.android.myapex"], + } + `) + }) - // platform jar in the framework boot image => ok - transform = func(config *dexpreopt.GlobalConfig) { - config.BootJars = []string{"some-platform-lib"} - } - testNoUpdatableJarsInBootImage(t, "", bp, transform) + 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"], + } + `) + }) +} + +func TestUpdatable_should_set_min_sdk_version(t *testing.T) { + testApexError(t, `"myapex" .*: updatable: updatable APEXes should set min_sdk_version`, ` + apex { + name: "myapex", + key: "myapex.key", + updatable: true, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + `) +} + +func TestUpdatableDefault_should_set_min_sdk_version(t *testing.T) { + testApexError(t, `"myapex" .*: updatable: updatable APEXes should set min_sdk_version`, ` + apex { + name: "myapex", + key: "myapex.key", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + `) +} + +func TestNoUpdatableJarsInBootImage(t *testing.T) { + // Set the BootJars in dexpreopt.GlobalConfig and productVariables to the same value. This can + // result in an invalid configuration as it does not set the ArtApexJars and allows art apex + // modules to be included in the BootJars. + prepareSetBootJars := func(bootJars ...string) android.FixturePreparer { + return android.GroupFixturePreparers( + dexpreopt.FixtureSetBootJars(bootJars...), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BootJars = android.CreateTestConfiguredJarList(bootJars) + }), + ) + } + + // Set the ArtApexJars and BootJars in dexpreopt.GlobalConfig and productVariables all to the + // same value. This can result in an invalid configuration as it allows non art apex jars to be + // specified in the ArtApexJars configuration. + prepareSetArtJars := func(bootJars ...string) android.FixturePreparer { + return android.GroupFixturePreparers( + dexpreopt.FixtureSetArtBootJars(bootJars...), + dexpreopt.FixtureSetBootJars(bootJars...), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BootJars = android.CreateTestConfiguredJarList(bootJars) + }), + ) + } + + t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) { + preparer := java.FixtureConfigureBootJars("com.android.art.debug:some-art-lib") + fragment := java.ApexVariantReference{ + Apex: proptools.StringPtr("com.android.art.debug"), + Module: proptools.StringPtr("art-bootclasspath-fragment"), + } + testNoUpdatableJarsInBootImage(t, "", preparer, fragment) + }) + + t.Run("updatable jar from ART apex in the framework boot image => error", func(t *testing.T) { + err := `module "some-art-lib" from updatable apexes \["com.android.art.debug"\] is not allowed in the framework boot image` + // Update the dexpreopt BootJars directly. + preparer := prepareSetBootJars("com.android.art.debug:some-art-lib") + testNoUpdatableJarsInBootImage(t, err, preparer) + }) + + t.Run("updatable jar from some other apex in the ART boot image => error", func(t *testing.T) { + err := `ArtApexJars expects this to be in apex "some-updatable-apex" but this is only in apexes.*"com.android.art.debug"` + // Update the dexpreopt ArtApexJars directly. + preparer := prepareSetArtJars("some-updatable-apex:some-updatable-apex-lib") + testNoUpdatableJarsInBootImage(t, err, preparer) + }) + + t.Run("non-updatable jar from some other apex in the ART boot image => error", func(t *testing.T) { + err := `ArtApexJars expects this to be in apex "some-non-updatable-apex" but this is only in apexes.*"com.android.art.debug"` + // Update the dexpreopt ArtApexJars directly. + preparer := prepareSetArtJars("some-non-updatable-apex:some-non-updatable-apex-lib") + testNoUpdatableJarsInBootImage(t, err, preparer) + }) + + t.Run("updatable jar from some other apex in the framework boot image => error", func(t *testing.T) { + err := `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the framework boot image` + preparer := java.FixtureConfigureBootJars("some-updatable-apex:some-updatable-apex-lib") + testNoUpdatableJarsInBootImage(t, err, preparer) + }) + + t.Run("non-updatable jar from some other apex in the framework boot image => ok", func(t *testing.T) { + preparer := java.FixtureConfigureBootJars("some-non-updatable-apex:some-non-updatable-apex-lib") + fragment := java.ApexVariantReference{ + Apex: proptools.StringPtr("some-non-updatable-apex"), + Module: proptools.StringPtr("some-non-updatable-fragment"), + } + testNoUpdatableJarsInBootImage(t, "", preparer, fragment) + }) + + t.Run("nonexistent jar in the ART boot image => error", func(t *testing.T) { + err := `"platform-bootclasspath" depends on undefined module "nonexistent"` + preparer := java.FixtureConfigureBootJars("platform:nonexistent") + testNoUpdatableJarsInBootImage(t, err, preparer) + }) + + t.Run("nonexistent jar in the framework boot image => error", func(t *testing.T) { + err := `"platform-bootclasspath" depends on undefined module "nonexistent"` + preparer := java.FixtureConfigureBootJars("platform:nonexistent") + testNoUpdatableJarsInBootImage(t, err, preparer) + }) + + t.Run("platform jar in the ART boot image => error", func(t *testing.T) { + err := `ArtApexJars is invalid as it requests a platform variant of "some-platform-lib"` + // Update the dexpreopt ArtApexJars directly. + preparer := prepareSetArtJars("platform:some-platform-lib") + testNoUpdatableJarsInBootImage(t, err, preparer) + }) + + t.Run("platform jar in the framework boot image => ok", func(t *testing.T) { + preparer := java.FixtureConfigureBootJars("platform:some-platform-lib") + testNoUpdatableJarsInBootImage(t, "", preparer) + }) +} + +func TestDexpreoptAccessDexFilesFromPrebuiltApex(t *testing.T) { + preparer := java.FixtureConfigureBootJars("myapex:libfoo") + t.Run("prebuilt no source", func(t *testing.T) { + fragment := java.ApexVariantReference{ + Apex: proptools.StringPtr("myapex"), + Module: proptools.StringPtr("my-bootclasspath-fragment"), + } + + testDexpreoptWithApexes(t, ` + prebuilt_apex { + name: "myapex" , + arch: { + arm64: { + src: "myapex-arm64.apex", + }, + arm: { + src: "myapex-arm.apex", + }, + }, + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + } + + prebuilt_bootclasspath_fragment { + name: "my-bootclasspath-fragment", + contents: ["libfoo"], + apex_available: ["myapex"], + } + + java_import { + name: "libfoo", + jars: ["libfoo.jar"], + apex_available: ["myapex"], + } + `, "", preparer, fragment) + }) } func testApexPermittedPackagesRules(t *testing.T, errmsg, bp string, apexBootJars []string, rules []android.Rule) { t.Helper() - android.ClearApexDependency() bp += ` apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", }` - fs := map[string][]byte{ + fs := android.MockFS{ "lib1/src/A.java": nil, "lib2/src/B.java": nil, "system/sepolicy/apex/myapex-file_contexts": nil, } - ctx := android.NewTestArchContext() - ctx.RegisterModuleType("apex", BundleFactory) - ctx.RegisterModuleType("apex_key", ApexKeyFactory) - ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) - cc.RegisterRequiredBuildComponentsForTest(ctx) - java.RegisterJavaBuildComponents(ctx) - java.RegisterSystemModulesBuildComponents(ctx) - java.RegisterDexpreoptBootJarsComponents(ctx) - ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators) - ctx.PreDepsMutators(RegisterPreDepsMutators) - ctx.PostDepsMutators(RegisterPostDepsMutators) - ctx.PostDepsMutators(android.RegisterNeverallowMutator) - - config := android.TestArchConfig(buildDir, nil, bp, fs) - android.SetTestNeverallowRules(config, rules) - updatableBootJars := make([]string, 0, len(apexBootJars)) - for _, apexBootJar := range apexBootJars { - updatableBootJars = append(updatableBootJars, "myapex:"+apexBootJar) + errorHandler := android.FixtureExpectsNoErrors + if errmsg != "" { + errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(errmsg) } - config.TestProductVariables.UpdatableBootJars = updatableBootJars - - ctx.Register(config) - _, errs := ctx.ParseBlueprintsFiles("Android.bp") - android.FailIfErrored(t, errs) - - _, errs = ctx.PrepareBuildActions(config) - if errmsg == "" { - android.FailIfErrored(t, errs) - } else if len(errs) > 0 { - android.FailIfNoMatchingErrors(t, errmsg, errs) - return - } else { - t.Fatalf("missing expected error %q (0 errors are returned)", errmsg) - } + android.GroupFixturePreparers( + android.PrepareForTestWithAndroidBuildComponents, + java.PrepareForTestWithJavaBuildComponents, + PrepareForTestWithApexBuildComponents, + android.PrepareForTestWithNeverallowRules(rules), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + updatableBootJars := make([]string, 0, len(apexBootJars)) + for _, apexBootJar := range apexBootJars { + updatableBootJars = append(updatableBootJars, "myapex:"+apexBootJar) + } + variables.UpdatableBootJars = android.CreateTestConfiguredJarList(updatableBootJars) + }), + fs.AddToFixture(), + ). + ExtendWithErrorHandler(errorHandler). + RunTestWithBp(t, bp) } func TestApexPermittedPackagesRules(t *testing.T) { @@ -4945,6 +6869,7 @@ func TestApexPermittedPackagesRules(t *testing.T) { name: "myapex", key: "myapex.key", java_libs: ["bcp_lib1", "nonbcp_lib2"], + updatable: false, }`, bootJars: []string{"bcp_lib1"}, modulesPackages: map[string][]string{ @@ -4977,6 +6902,7 @@ func TestApexPermittedPackagesRules(t *testing.T) { name: "myapex", key: "myapex.key", java_libs: ["bcp_lib1", "bcp_lib2"], + updatable: false, } `, bootJars: []string{"bcp_lib1", "bcp_lib2"}, @@ -4996,11 +6922,12 @@ func TestApexPermittedPackagesRules(t *testing.T) { } func TestTestFor(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib", "myprivlib"], + updatable: false, } apex_key { @@ -5035,16 +6962,150 @@ func TestTestFor(t *testing.T) { srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", - shared_libs: ["mylib", "myprivlib"], + shared_libs: ["mylib", "myprivlib", "mytestlib"], test_for: ["myapex"] } + + cc_library { + name: "mytestlib", + srcs: ["mylib.cpp"], + system_shared_libs: [], + shared_libs: ["mylib", "myprivlib"], + stl: "none", + test_for: ["myapex"], + } + + cc_benchmark { + name: "mybench", + srcs: ["mylib.cpp"], + system_shared_libs: [], + shared_libs: ["mylib", "myprivlib"], + stl: "none", + test_for: ["myapex"], + } `) - // the test 'mytest' is a test for the apex, therefore is linked to the + ensureLinkedLibIs := func(mod, variant, linkedLib, expectedVariant string) { + ldFlags := strings.Split(ctx.ModuleForTests(mod, variant).Rule("ld").Args["libFlags"], " ") + mylibLdFlags := android.FilterListPred(ldFlags, func(s string) bool { return strings.HasPrefix(s, linkedLib) }) + android.AssertArrayString(t, "unexpected "+linkedLib+" link library for "+mod, []string{linkedLib + expectedVariant}, mylibLdFlags) + } + + // These modules are tests for the apex, therefore are linked to the // actual implementation of mylib instead of its stub. - ldFlags := ctx.ModuleForTests("mytest", "android_arm64_armv8-a").Rule("ld").Args["libFlags"] - ensureContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared/mylib.so") - ensureNotContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared_1/mylib.so") + ensureLinkedLibIs("mytest", "android_arm64_armv8-a", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so") + ensureLinkedLibIs("mytestlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so") + ensureLinkedLibIs("mybench", "android_arm64_armv8-a", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so") +} + +func TestIndirectTestFor(t *testing.T) { + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib", "myprivlib"], + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + stubs: { + versions: ["1"], + }, + apex_available: ["myapex"], + } + + cc_library { + name: "myprivlib", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + shared_libs: ["mylib"], + apex_available: ["myapex"], + } + + cc_library { + name: "mytestlib", + srcs: ["mylib.cpp"], + system_shared_libs: [], + shared_libs: ["myprivlib"], + stl: "none", + test_for: ["myapex"], + } + `) + + ensureLinkedLibIs := func(mod, variant, linkedLib, expectedVariant string) { + ldFlags := strings.Split(ctx.ModuleForTests(mod, variant).Rule("ld").Args["libFlags"], " ") + mylibLdFlags := android.FilterListPred(ldFlags, func(s string) bool { return strings.HasPrefix(s, linkedLib) }) + android.AssertArrayString(t, "unexpected "+linkedLib+" link library for "+mod, []string{linkedLib + expectedVariant}, mylibLdFlags) + } + + // The platform variant of mytestlib links to the platform variant of the + // internal myprivlib. + ensureLinkedLibIs("mytestlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/myprivlib/", "android_arm64_armv8-a_shared/myprivlib.so") + + // The platform variant of myprivlib links to the platform variant of mylib + // and bypasses its stubs. + ensureLinkedLibIs("myprivlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so") +} + +func TestTestForForLibInOtherApex(t *testing.T) { + // This case is only allowed for known overlapping APEXes, i.e. the ART APEXes. + _ = testApex(t, ` + apex { + name: "com.android.art", + key: "myapex.key", + native_shared_libs: ["mylib"], + updatable: false, + } + + apex { + name: "com.android.art.debug", + key: "myapex.key", + native_shared_libs: ["mylib", "mytestlib"], + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + stubs: { + versions: ["1"], + }, + apex_available: ["com.android.art", "com.android.art.debug"], + } + + cc_library { + name: "mytestlib", + srcs: ["mylib.cpp"], + system_shared_libs: [], + shared_libs: ["mylib"], + stl: "none", + apex_available: ["com.android.art.debug"], + test_for: ["com.android.art"], + } + `, + android.MockFS{ + "system/sepolicy/apex/com.android.art-file_contexts": nil, + "system/sepolicy/apex/com.android.art.debug-file_contexts": nil, + }.AddToFixture()) } // TODO(jungjw): Move this to proptools @@ -5053,25 +7114,29 @@ func intPtr(i int) *int { } func TestApexSet(t *testing.T) { - ctx, config := testApex(t, ` + ctx := testApex(t, ` apex_set { name: "myapex", set: "myapex.apks", filename: "foo_v2.apex", overrides: ["foo"], } - `, func(fs map[string][]byte, config android.Config) { - config.TestProductVariables.Platform_sdk_version = intPtr(30) - config.Targets[android.Android] = []android.Target{ - {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}}, - {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}}, - } - }) + `, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.Platform_sdk_version = intPtr(30) + }), + android.FixtureModifyConfig(func(config android.Config) { + config.Targets[android.Android] = []android.Target{ + {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}}, + {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}}, + } + }), + ) - m := ctx.ModuleForTests("myapex", "android_common") + m := ctx.ModuleForTests("myapex.apex.extractor", "android_common") // Check extract_apks tool parameters. - extractedApex := m.Output(buildDir + "/.intermediates/myapex/android_common/foo_v2.apex") + extractedApex := m.Output("extracted/myapex.apks") actual := extractedApex.Args["abis"] expected := "ARMEABI_V7A,ARM64_V8A" if actual != expected { @@ -5083,19 +7148,58 @@ func TestApexSet(t *testing.T) { t.Errorf("Unexpected abis parameter - expected %q vs actual %q", expected, actual) } + m = ctx.ModuleForTests("myapex", "android_common_myapex") a := m.Module().(*ApexSet) expectedOverrides := []string{"foo"} - actualOverrides := android.AndroidMkEntriesForTest(t, config, "", a)[0].EntryMap["LOCAL_OVERRIDES_MODULES"] + actualOverrides := android.AndroidMkEntriesForTest(t, ctx, a)[0].EntryMap["LOCAL_OVERRIDES_MODULES"] if !reflect.DeepEqual(actualOverrides, expectedOverrides) { t.Errorf("Incorrect LOCAL_OVERRIDES_MODULES - expected %q vs actual %q", expectedOverrides, actualOverrides) } } +func TestNoStaticLinkingToStubsLib(t *testing.T) { + testApexError(t, `.*required by "mylib" is a native library providing stub.*`, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib"], + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + static_libs: ["otherlib"], + system_shared_libs: [], + stl: "none", + apex_available: [ "myapex" ], + } + + cc_library { + name: "otherlib", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + stubs: { + versions: ["1", "2", "3"], + }, + apex_available: [ "myapex" ], + } + `) +} + func TestApexKeysTxt(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", + updatable: false, } apex_key { @@ -5132,12 +7236,13 @@ func TestApexKeysTxt(t *testing.T) { } func TestAllowedFiles(t *testing.T) { - ctx, _ := testApex(t, ` + ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", apps: ["app"], allowed_files: "allowed.txt", + updatable: false, } apex_key { @@ -5186,13 +7291,416 @@ func TestAllowedFiles(t *testing.T) { } } -func TestMain(m *testing.M) { - run := func() int { - setUp() - defer tearDown() +func TestNonPreferredPrebuiltDependency(t *testing.T) { + testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib"], + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + stubs: { + versions: ["current"], + }, + apex_available: ["myapex"], + } + + cc_prebuilt_library_shared { + name: "mylib", + prefer: false, + srcs: ["prebuilt.so"], + stubs: { + versions: ["current"], + }, + apex_available: ["myapex"], + } + `) +} + +func TestCompressedApex(t *testing.T) { + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + compressible: true, + updatable: false, + } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + `, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.CompressedApex = proptools.BoolPtr(true) + }), + ) + + compressRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("compressRule") + ensureContains(t, compressRule.Output.String(), "myapex.capex.unsigned") + + signApkRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Description("sign compressedApex") + ensureEquals(t, signApkRule.Input.String(), compressRule.Output.String()) + + // Make sure output of bundle is .capex + ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + ensureContains(t, ab.outputFile.String(), "myapex.capex") + + // Verify android.mk rules + data := android.AndroidMkDataForTest(t, ctx, ab) + var builder strings.Builder + data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data) + androidMk := builder.String() + ensureContains(t, androidMk, "LOCAL_MODULE_STEM := myapex.capex\n") +} + +func TestPreferredPrebuiltSharedLibDep(t *testing.T) { + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib"], + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + apex_available: ["myapex"], + shared_libs: ["otherlib"], + system_shared_libs: [], + } + + cc_library { + name: "otherlib", + srcs: ["mylib.cpp"], + stubs: { + versions: ["current"], + }, + } + + cc_prebuilt_library_shared { + name: "otherlib", + prefer: true, + srcs: ["prebuilt.so"], + stubs: { + versions: ["current"], + }, + } + `) + + ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + data := android.AndroidMkDataForTest(t, ctx, ab) + var builder strings.Builder + data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data) + androidMk := builder.String() + + // The make level dependency needs to be on otherlib - prebuilt_otherlib isn't + // a thing there. + ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += otherlib\n") +} + +func TestExcludeDependency(t *testing.T) { + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib"], + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } - return m.Run() + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: ["myapex"], + shared_libs: ["mylib2"], + target: { + apex: { + exclude_shared_libs: ["mylib2"], + }, + }, + } + + cc_library { + name: "mylib2", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + } + `) + + // Check if mylib is linked to mylib2 for the non-apex target + ldFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"] + ensureContains(t, ldFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so") + + // Make sure that the link doesn't occur for the apex target + ldFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] + ensureNotContains(t, ldFlags, "mylib2/android_arm64_armv8-a_shared_apex10000/mylib2.so") + + // It shouldn't appear in the copy cmd as well. + copyCmds := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule").Args["copy_commands"] + ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so") +} + +func TestPrebuiltStubLibDep(t *testing.T) { + bpBase := ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib"], + updatable: false, + } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + apex_available: ["myapex"], + shared_libs: ["stublib"], + system_shared_libs: [], + } + apex { + name: "otherapex", + enabled: %s, + key: "myapex.key", + native_shared_libs: ["stublib"], + updatable: false, + } + ` + + stublibSourceBp := ` + cc_library { + name: "stublib", + srcs: ["mylib.cpp"], + apex_available: ["otherapex"], + system_shared_libs: [], + stl: "none", + stubs: { + versions: ["1"], + }, + } + ` + + stublibPrebuiltBp := ` + cc_prebuilt_library_shared { + name: "stublib", + srcs: ["prebuilt.so"], + apex_available: ["otherapex"], + stubs: { + versions: ["1"], + }, + %s + } + ` + + tests := []struct { + name string + stublibBp string + usePrebuilt bool + modNames []string // Modules to collect AndroidMkEntries for + otherApexEnabled []string + }{ + { + name: "only_source", + stublibBp: stublibSourceBp, + usePrebuilt: false, + modNames: []string{"stublib"}, + otherApexEnabled: []string{"true", "false"}, + }, + { + name: "source_preferred", + stublibBp: stublibSourceBp + fmt.Sprintf(stublibPrebuiltBp, ""), + usePrebuilt: false, + modNames: []string{"stublib", "prebuilt_stublib"}, + otherApexEnabled: []string{"true", "false"}, + }, + { + name: "prebuilt_preferred", + stublibBp: stublibSourceBp + fmt.Sprintf(stublibPrebuiltBp, "prefer: true,"), + usePrebuilt: true, + modNames: []string{"stublib", "prebuilt_stublib"}, + otherApexEnabled: []string{"false"}, // No "true" since APEX cannot depend on prebuilt. + }, + { + name: "only_prebuilt", + stublibBp: fmt.Sprintf(stublibPrebuiltBp, ""), + usePrebuilt: true, + modNames: []string{"stublib"}, + otherApexEnabled: []string{"false"}, // No "true" since APEX cannot depend on prebuilt. + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + for _, otherApexEnabled := range test.otherApexEnabled { + t.Run("otherapex_enabled_"+otherApexEnabled, func(t *testing.T) { + ctx := testApex(t, fmt.Sprintf(bpBase, otherApexEnabled)+test.stublibBp) + + type modAndMkEntries struct { + mod *cc.Module + mkEntries android.AndroidMkEntries + } + entries := []*modAndMkEntries{} + + // Gather shared lib modules that are installable + for _, modName := range test.modNames { + for _, variant := range ctx.ModuleVariantsForTests(modName) { + if !strings.HasPrefix(variant, "android_arm64_armv8-a_shared") { + continue + } + mod := ctx.ModuleForTests(modName, variant).Module().(*cc.Module) + if !mod.Enabled() || mod.IsHideFromMake() { + continue + } + for _, ent := range android.AndroidMkEntriesForTest(t, ctx, mod) { + if ent.Disabled { + continue + } + entries = append(entries, &modAndMkEntries{ + mod: mod, + mkEntries: ent, + }) + } + } + } + + var entry *modAndMkEntries = nil + for _, ent := range entries { + if strings.Join(ent.mkEntries.EntryMap["LOCAL_MODULE"], ",") == "stublib" { + if entry != nil { + t.Errorf("More than one AndroidMk entry for \"stublib\": %s and %s", entry.mod, ent.mod) + } else { + entry = ent + } + } + } + + if entry == nil { + t.Errorf("AndroidMk entry for \"stublib\" missing") + } else { + isPrebuilt := entry.mod.Prebuilt() != nil + if isPrebuilt != test.usePrebuilt { + t.Errorf("Wrong module for \"stublib\" AndroidMk entry: got prebuilt %t, want prebuilt %t", isPrebuilt, test.usePrebuilt) + } + if !entry.mod.IsStubs() { + t.Errorf("Module for \"stublib\" AndroidMk entry isn't a stub: %s", entry.mod) + } + if entry.mkEntries.EntryMap["LOCAL_NOT_AVAILABLE_FOR_PLATFORM"] != nil { + t.Errorf("AndroidMk entry for \"stublib\" has LOCAL_NOT_AVAILABLE_FOR_PLATFORM set: %+v", entry.mkEntries) + } + cflags := entry.mkEntries.EntryMap["LOCAL_EXPORT_CFLAGS"] + expected := "-D__STUBLIB_API__=10000" + if !android.InList(expected, cflags) { + t.Errorf("LOCAL_EXPORT_CFLAGS expected to have %q, but got %q", expected, cflags) + } + } + }) + } + }) + } +} + +func TestApexJavaCoverage(t *testing.T) { + bp := ` + apex { + name: "myapex", + key: "myapex.key", + java_libs: ["mylib"], + bootclasspath_fragments: ["mybootclasspathfragment"], + systemserverclasspath_fragments: ["mysystemserverclasspathfragment"], + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + java_library { + name: "mylib", + srcs: ["mylib.java"], + apex_available: ["myapex"], + compile_dex: true, + } + + bootclasspath_fragment { + name: "mybootclasspathfragment", + contents: ["mybootclasspathlib"], + apex_available: ["myapex"], + } + + java_library { + name: "mybootclasspathlib", + srcs: ["mybootclasspathlib.java"], + apex_available: ["myapex"], + compile_dex: true, + } + + systemserverclasspath_fragment { + name: "mysystemserverclasspathfragment", + contents: ["mysystemserverclasspathlib"], + apex_available: ["myapex"], + } + + java_library { + name: "mysystemserverclasspathlib", + srcs: ["mysystemserverclasspathlib.java"], + apex_available: ["myapex"], + compile_dex: true, + } + ` + + result := android.GroupFixturePreparers( + PrepareForTestWithApexBuildComponents, + prepareForTestWithMyapex, + java.PrepareForTestWithJavaDefaultModules, + android.PrepareForTestWithAndroidBuildComponents, + android.FixtureWithRootAndroidBp(bp), + android.FixtureMergeEnv(map[string]string{ + "EMMA_INSTRUMENT": "true", + }), + ).RunTest(t) + + // Make sure jacoco ran on both mylib and mybootclasspathlib + if result.ModuleForTests("mylib", "android_common_apex10000").MaybeRule("jacoco").Rule == nil { + t.Errorf("Failed to find jacoco rule for mylib") } + if result.ModuleForTests("mybootclasspathlib", "android_common_apex10000").MaybeRule("jacoco").Rule == nil { + t.Errorf("Failed to find jacoco rule for mybootclasspathlib") + } + if result.ModuleForTests("mysystemserverclasspathlib", "android_common_apex10000").MaybeRule("jacoco").Rule == nil { + t.Errorf("Failed to find jacoco rule for mysystemserverclasspathlib") + } +} - os.Exit(run()) +func TestMain(m *testing.M) { + os.Exit(m.Run()) } |