// Copyright 2018 Google Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package apex import ( "bufio" "bytes" "io/ioutil" "os" "strings" "testing" "github.com/google/blueprint/proptools" "android/soong/android" "android/soong/cc" "android/soong/java" ) func testApex(t *testing.T, bp string) *android.TestContext { config, buildDir := setup(t) defer teardown(buildDir) ctx := android.NewTestArchContext() ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apexBundleFactory)) ctx.RegisterModuleType("apex_test", android.ModuleFactoryAdaptor(testApexBundleFactory)) ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apexKeyFactory)) ctx.RegisterModuleType("apex_defaults", android.ModuleFactoryAdaptor(defaultsFactory)) ctx.RegisterModuleType("prebuilt_apex", android.ModuleFactoryAdaptor(PrebuiltFactory)) ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.TopDown("apex_deps", apexDepsMutator) ctx.BottomUp("apex", apexMutator) ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel() ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel() }) ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory)) ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(cc.LibrarySharedFactory)) ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(cc.LibraryHeaderFactory)) ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(cc.BinaryFactory)) ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory)) ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory)) ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory)) ctx.RegisterModuleType("prebuilt_etc", android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory)) ctx.RegisterModuleType("sh_binary", android.ModuleFactoryAdaptor(android.ShBinaryFactory)) ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(java.AndroidAppCertificateFactory)) ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory)) ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("prebuilts", android.PrebuiltMutator).Parallel() }) ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("image", cc.ImageMutator).Parallel() ctx.BottomUp("link", cc.LinkageMutator).Parallel() ctx.BottomUp("vndk", cc.VndkMutator).Parallel() ctx.BottomUp("version", cc.VersionMutator).Parallel() ctx.BottomUp("begin", cc.BeginMutator).Parallel() }) ctx.Register() bp = bp + ` toolchain_library { name: "libcompiler_rt-extras", src: "", vendor_available: true, recovery_available: true, } toolchain_library { name: "libatomic", src: "", vendor_available: true, recovery_available: true, } toolchain_library { name: "libgcc", src: "", vendor_available: true, recovery_available: true, } toolchain_library { name: "libclang_rt.builtins-aarch64-android", src: "", vendor_available: true, recovery_available: true, } toolchain_library { name: "libclang_rt.builtins-arm-android", src: "", vendor_available: true, recovery_available: true, } cc_object { name: "crtbegin_so", stl: "none", vendor_available: true, recovery_available: true, } cc_object { name: "crtend_so", stl: "none", vendor_available: true, recovery_available: true, } cc_object { name: "crtbegin_static", stl: "none", } cc_object { name: "crtend_android", stl: "none", } llndk_library { name: "libc", symbol_file: "", } llndk_library { name: "libm", symbol_file: "", } llndk_library { name: "libdl", symbol_file: "", } ` ctx.MockFileSystem(map[string][]byte{ "Android.bp": []byte(bp), "build/target/product/security": nil, "apex_manifest.json": nil, "AndroidManifest.xml": nil, "system/sepolicy/apex/myapex-file_contexts": nil, "system/sepolicy/apex/myapex_keytest-file_contexts": nil, "system/sepolicy/apex/otherapex-file_contexts": nil, "mylib.cpp": nil, "myprebuilt": nil, "my_include": nil, "vendor/foo/devkeys/test.x509.pem": nil, "vendor/foo/devkeys/test.pk8": nil, "testkey.x509.pem": nil, "testkey.pk8": nil, "testkey.override.x509.pem": nil, "testkey.override.pk8": nil, "vendor/foo/devkeys/testkey.avbpubkey": nil, "vendor/foo/devkeys/testkey.pem": nil, "NOTICE": nil, "custom_notice": nil, "testkey2.avbpubkey": nil, "testkey2.pem": nil, "myapex-arm64.apex": nil, "myapex-arm.apex": nil, }) _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) android.FailIfErrored(t, errs) _, errs = ctx.PrepareBuildActions(config) android.FailIfErrored(t, errs) return ctx } func setup(t *testing.T) (config android.Config, buildDir string) { buildDir, err := ioutil.TempDir("", "soong_apex_test") if err != nil { t.Fatal(err) } config = android.TestArchConfig(buildDir, nil) config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current") config.TestProductVariables.DefaultAppCertificate = proptools.StringPtr("vendor/foo/devkeys/test") config.TestProductVariables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"} return } func teardown(buildDir string) { os.RemoveAll(buildDir) } // ensure that 'result' contains 'expected' func ensureContains(t *testing.T, result string, expected string) { if !strings.Contains(result, expected) { t.Errorf("%q is not found in %q", expected, result) } } // ensures that 'result' does not contain 'notExpected' func ensureNotContains(t *testing.T, result string, notExpected string) { if strings.Contains(result, notExpected) { t.Errorf("%q is found in %q", notExpected, result) } } func ensureListContains(t *testing.T, result []string, expected string) { if !android.InList(expected, result) { t.Errorf("%q is not found in %v", expected, result) } } func ensureListNotContains(t *testing.T, result []string, notExpected string) { if android.InList(notExpected, result) { t.Errorf("%q is found in %v", notExpected, result) } } // Minimal test func TestBasicApex(t *testing.T) { ctx := testApex(t, ` apex_defaults { name: "myapex-defaults", manifest: ":myapex.manifest", androidManifest: ":myapex.androidmanifest", key: "myapex.key", native_shared_libs: ["mylib"], multilib: { both: { binaries: ["foo",], } } } apex { name: "myapex", defaults: ["myapex-defaults"], } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } filegroup { name: "myapex.manifest", srcs: ["apex_manifest.json"], } filegroup { name: "myapex.androidmanifest", srcs: ["AndroidManifest.xml"], } cc_library { name: "mylib", srcs: ["mylib.cpp"], shared_libs: ["mylib2"], system_shared_libs: [], stl: "none", } cc_binary { name: "foo", srcs: ["mylib.cpp"], compile_multilib: "both", multilib: { lib32: { suffix: "32", }, lib64: { suffix: "64", }, }, symlinks: ["foo_link_"], symlink_preferred_arch: true, system_shared_libs: [], static_executable: true, stl: "none", } cc_library { name: "mylib2", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", notice: "custom_notice", } `) apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") optFlags := apexRule.Args["opt_flags"] ensureContains(t, optFlags, "--pubkey vendor/foo/devkeys/testkey.avbpubkey") copyCmds := apexRule.Args["copy_commands"] // Ensure that main rule creates an output 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_core_shared_myapex") // Ensure that apex variant is created for the indirect dep ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_core_shared_myapex") // 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") // Ensure that the platform variant ends with _core_shared ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_core_shared") ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_core_shared") // Ensure that all symlinks are present. found_foo_link_64 := false found_foo := false for _, cmd := range strings.Split(copyCmds, " && ") { if strings.HasPrefix(cmd, "ln -s foo64") { if strings.HasSuffix(cmd, "bin/foo") { found_foo = true } else if strings.HasSuffix(cmd, "bin/foo_link_64") { found_foo_link_64 = true } } } good := found_foo && found_foo_link_64 if !good { t.Errorf("Could not find all expected symlinks! foo: %t, foo_link_64: %t. Command was %s", found_foo, found_foo_link_64, copyCmds) } apexMergeNoticeRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexMergeNoticeRule") noticeInputs := strings.Split(apexMergeNoticeRule.Args["inputs"], " ") if len(noticeInputs) != 3 { t.Errorf("number of input notice files: expected = 3, actual = %d", len(noticeInputs)) } ensureListContains(t, noticeInputs, "NOTICE") ensureListContains(t, noticeInputs, "custom_notice") } func TestBasicZipApex(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", payload_type: "zip", native_shared_libs: ["mylib"], } 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", } cc_library { name: "mylib2", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", } `) zipApexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("zipApexRule") copyCmds := zipApexRule.Args["copy_commands"] // Ensure that main rule creates an output 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_core_shared_myapex") // Ensure that APEX variant is created for the indirect dep ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_core_shared_myapex") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.zipapex/lib64/mylib.so") ensureContains(t, copyCmds, "image.zipapex/lib64/mylib2.so") } func TestApexWithStubs(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib", "mylib3"], } 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", } cc_library { name: "mylib2", srcs: ["mylib.cpp"], cflags: ["-include mylib.h"], system_shared_libs: [], stl: "none", stubs: { versions: ["1", "2", "3"], }, } cc_library { name: "mylib3", srcs: ["mylib.cpp"], shared_libs: ["mylib4"], system_shared_libs: [], stl: "none", stubs: { versions: ["10", "11", "12"], }, } cc_library { name: "mylib4", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", } `) apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").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_core_shared_myapex").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_core_shared_3_myapex/mylib2.so") // ... and not linking to the non-stub (impl) variant of mylib2 ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_core_shared_myapex/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_core_shared_myapex/mylib3.so") // .. and not linking to the stubs variant of mylib3 ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_core_shared_12_myapex/mylib3.so") // Ensure that stubs libs are built without -include flags mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_core_static_myapex").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_core_static_3_myapex").Rule("genStubSrc").Args["flags"]) } func TestApexWithExplicitStubsDependency(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library { name: "mylib", srcs: ["mylib.cpp"], shared_libs: ["libfoo#10"], system_shared_libs: [], stl: "none", } cc_library { name: "libfoo", srcs: ["mylib.cpp"], shared_libs: ["libbar"], system_shared_libs: [], stl: "none", stubs: { versions: ["10", "20", "30"], }, } cc_library { name: "libbar", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", } `) apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").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/libfoo.so") // Ensure that dependency of stubs is not included ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so") mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_core_shared_myapex").Rule("ld").Args["libFlags"] // Ensure that mylib is linking with version 10 of libfoo ensureContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_core_shared_10_myapex/libfoo.so") // ... and not linking to the non-stub (impl) variant of libfoo ensureNotContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_core_shared_myapex/libfoo.so") libFooStubsLdFlags := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_core_shared_10_myapex").Rule("ld").Args["libFlags"] // Ensure that libfoo stubs is not linking to libbar (since it is a stubs) ensureNotContains(t, libFooStubsLdFlags, "libbar.so") } func TestApexWithSystemLibsStubs(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib", "mylib_shared", "libdl", "libm"], } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library { name: "mylib", srcs: ["mylib.cpp"], shared_libs: ["libdl#27"], stl: "none", } cc_library_shared { name: "mylib_shared", srcs: ["mylib.cpp"], shared_libs: ["libdl#27"], stl: "none", } cc_library { name: "libc", no_libgcc: true, nocrt: true, system_shared_libs: [], stl: "none", stubs: { versions: ["27", "28", "29"], }, } cc_library { name: "libm", no_libgcc: true, nocrt: true, system_shared_libs: [], stl: "none", stubs: { versions: ["27", "28", "29"], }, } cc_library { name: "libdl", no_libgcc: true, nocrt: true, system_shared_libs: [], stl: "none", stubs: { versions: ["27", "28", "29"], }, } cc_library { name: "libBootstrap", srcs: ["mylib.cpp"], stl: "none", bootstrap: true, } `) apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that mylib, libm, libdl are included. ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") ensureContains(t, copyCmds, "image.apex/lib64/bionic/libm.so") ensureContains(t, copyCmds, "image.apex/lib64/bionic/libdl.so") // 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_core_shared_myapex").Rule("ld").Args["libFlags"] mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_core_static_myapex").Rule("cc").Args["cFlags"] mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_core_shared_myapex").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_core_shared_29_myapex/libc.so") // ... and not linking to the non-stub (impl) variant ensureNotContains(t, mylibLdFlags, "libc/android_arm64_armv8-a_core_shared_myapex/libc.so") // ... Cflags from stub is correctly exported to mylib ensureContains(t, mylibCFlags, "__LIBC_API__=29") ensureContains(t, mylibSharedCFlags, "__LIBC_API__=29") // For dependency to libm // Ensure that mylib is linking with the non-stub (impl) variant ensureContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_core_shared_myapex/libm.so") // ... and not linking to the stub variant ensureNotContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_core_shared_29_myapex/libm.so") // ... and is not compiling with the stub ensureNotContains(t, mylibCFlags, "__LIBM_API__=29") ensureNotContains(t, mylibSharedCFlags, "__LIBM_API__=29") // For dependency to libdl // Ensure that mylib is linking with the specified version of stubs ensureContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_core_shared_27_myapex/libdl.so") // ... and not linking to the other versions of stubs ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_core_shared_28_myapex/libdl.so") ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_core_shared_29_myapex/libdl.so") // ... and not linking to the non-stub (impl) variant ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_core_shared_myapex/libdl.so") // ... Cflags from stub is correctly exported to mylib ensureContains(t, mylibCFlags, "__LIBDL_API__=27") ensureContains(t, mylibSharedCFlags, "__LIBDL_API__=27") // Ensure that libBootstrap is depending on the platform variant of bionic libs libFlags := ctx.ModuleForTests("libBootstrap", "android_arm64_armv8-a_core_shared").Rule("ld").Args["libFlags"] ensureContains(t, libFlags, "libc/android_arm64_armv8-a_core_shared/libc.so") ensureContains(t, libFlags, "libm/android_arm64_armv8-a_core_shared/libm.so") ensureContains(t, libFlags, "libdl/android_arm64_armv8-a_core_shared/libdl.so") } func TestFilesInSubDir(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], binaries: ["mybin"], prebuilts: ["myetc"], compile_multilib: "both", } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } prebuilt_etc { name: "myetc", src: "myprebuilt", sub_dir: "foo/bar", } cc_library { name: "mylib", srcs: ["mylib.cpp"], relative_install_path: "foo/bar", system_shared_libs: [], stl: "none", } cc_binary { name: "mybin", srcs: ["mylib.cpp"], relative_install_path: "foo/bar", system_shared_libs: [], static_executable: true, stl: "none", } `) generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("generateFsConfig") dirs := strings.Split(generateFsRule.Args["exec_paths"], " ") // Ensure that the subdirectories are all listed ensureListContains(t, dirs, "etc") ensureListContains(t, dirs, "etc/foo") ensureListContains(t, dirs, "etc/foo/bar") ensureListContains(t, dirs, "lib64") ensureListContains(t, dirs, "lib64/foo") ensureListContains(t, dirs, "lib64/foo/bar") ensureListContains(t, dirs, "lib") ensureListContains(t, dirs, "lib/foo") ensureListContains(t, dirs, "lib/foo/bar") ensureListContains(t, dirs, "bin") ensureListContains(t, dirs, "bin/foo") ensureListContains(t, dirs, "bin/foo/bar") } func TestUseVendor(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], use_vendor: true, } 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: [], vendor_available: true, stl: "none", } cc_library { name: "mylib2", srcs: ["mylib.cpp"], system_shared_libs: [], vendor_available: true, stl: "none", } `) inputsList := []string{} for _, i := range ctx.ModuleForTests("myapex", "android_common_myapex").Module().BuildParamsForTests() { for _, implicit := range i.Implicits { inputsList = append(inputsList, implicit.String()) } } inputsString := strings.Join(inputsList, " ") // ensure that the apex includes vendor variants of the direct and indirect deps ensureContains(t, inputsString, "android_arm64_armv8-a_vendor_shared_myapex/mylib.so") ensureContains(t, inputsString, "android_arm64_armv8-a_vendor_shared_myapex/mylib2.so") // ensure that the apex does not include core variants ensureNotContains(t, inputsString, "android_arm64_armv8-a_core_shared_myapex/mylib.so") ensureNotContains(t, inputsString, "android_arm64_armv8-a_core_shared_myapex/mylib2.so") } func TestStaticLinking(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], } 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", "2", "3"], }, } cc_binary { name: "not_in_apex", srcs: ["mylib.cpp"], static_libs: ["mylib"], static_executable: true, system_shared_libs: [], stl: "none", } `) ldFlags := ctx.ModuleForTests("not_in_apex", "android_arm64_armv8-a_core").Rule("ld").Args["libFlags"] // Ensure that not_in_apex is linking with the static variant of mylib ensureContains(t, ldFlags, "mylib/android_arm64_armv8-a_core_static/mylib.a") } func TestKeys(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex_keytest", key: "myapex.key", certificate: ":myapex.certificate", native_shared_libs: ["mylib"], } cc_library { name: "mylib", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } android_app_certificate { name: "myapex.certificate", certificate: "testkey", } android_app_certificate { name: "myapex.certificate.override", certificate: "testkey.override", } `) // 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(), "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(), "vendor/foo/devkeys/testkey.pem") } // check the APK certs. It should be overridden to myapex.certificate.override certs := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk").Args["certificates"] if certs != "testkey.override.x509.pem testkey.override.pk8" { t.Errorf("cert and private key %q are not %q", certs, "testkey.override.509.pem testkey.override.pk8") } } func TestMacro(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], } apex { name: "otherapex", key: "myapex.key", native_shared_libs: ["mylib"], } 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", } `) // non-APEX variant does not have __ANDROID__APEX__ defined mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_core_static").Rule("cc").Args["cFlags"] ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__=myapex") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__=otherapex") // APEX variant has __ANDROID_APEX__= defined mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_core_static_myapex").Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__=myapex") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__=otherapex") // APEX variant has __ANDROID_APEX__= defined mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_core_static_otherapex").Rule("cc").Args["cFlags"] ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__=myapex") ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__=otherapex") } func TestHeaderLibsDependency(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library_headers { name: "mylib_headers", export_include_dirs: ["my_include"], system_shared_libs: [], stl: "none", } cc_library { name: "mylib", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", header_libs: ["mylib_headers"], export_header_lib_headers: ["mylib_headers"], stubs: { versions: ["1", "2", "3"], }, } cc_library { name: "otherlib", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", shared_libs: ["mylib"], } `) cFlags := ctx.ModuleForTests("otherlib", "android_arm64_armv8-a_core_static").Rule("cc").Args["cFlags"] // Ensure that the include path of the header lib is exported to 'otherlib' ensureContains(t, cFlags, "-Imy_include") } func TestNonTestApex(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib_common"], } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library { name: "mylib_common", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", } `) module := ctx.ModuleForTests("myapex", "android_common_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] if apex, ok := module.Module().(*apexBundle); !ok || apex.testApex { t.Log("Apex was a test apex!") t.Fail() } // Ensure that main rule creates an output 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_core_shared_myapex") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.apex/lib64/mylib_common.so") // Ensure that the platform variant ends with _core_shared ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_core_shared") if !android.InAnyApex("mylib_common") { 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, ` apex_test { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib_common_test"], } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library { name: "mylib_common_test", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", } `) module := ctx.ModuleForTests("myapex", "android_common_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] if apex, ok := module.Module().(*apexBundle); !ok || !apex.testApex { t.Log("Apex was not a test apex!") t.Fail() } // Ensure that main rule creates an output 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_core_shared_myapex") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.apex/lib64/mylib_common_test.so") // Ensure that the platform variant ends with _core_shared ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_core_shared") if android.InAnyApex("mylib_common_test") { t.Log("Found mylib_common_test in some apex!") t.Fail() } } func TestApexWithTarget(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", multilib: { first: { native_shared_libs: ["mylib_common"], } }, target: { android: { multilib: { first: { native_shared_libs: ["mylib"], } } }, host: { multilib: { first: { native_shared_libs: ["mylib2"], } } } } } 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", } cc_library { name: "mylib_common", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", compile_multilib: "first", } cc_library { name: "mylib2", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", compile_multilib: "first", } `) apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that main rule creates an output 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_core_shared_myapex") ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_core_shared_myapex") ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_core_shared_myapex") // 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/mylib_common.so") ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so") // Ensure that the platform variant ends with _core_shared ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_core_shared") ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_core_shared") ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_core_shared") } func TestApexWithShBinary(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", binaries: ["myscript"], } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } sh_binary { name: "myscript", src: "mylib.cpp", filename: "myscript.sh", sub_dir: "script", } `) apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] ensureContains(t, copyCmds, "image.apex/bin/script/myscript.sh") } func TestApexInProductPartition(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], product_specific: true, } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", product_specific: true, } cc_library { name: "mylib", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", } `) apex := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) expected := "target/product/test_device/product/apex" actual := apex.installDir.RelPathString() if actual != expected { t.Errorf("wrong install path. expected %q. actual %q", expected, actual) } } func TestApexKeyFromOtherModule(t *testing.T) { ctx := testApex(t, ` apex_key { name: "myapex.key", public_key: ":my.avbpubkey", private_key: ":my.pem", product_specific: true, } filegroup { name: "my.avbpubkey", srcs: ["testkey2.avbpubkey"], } filegroup { name: "my.pem", srcs: ["testkey2.pem"], } `) apex_key := ctx.ModuleForTests("myapex.key", "android_common").Module().(*apexKey) expected_pubkey := "testkey2.avbpubkey" actual_pubkey := apex_key.public_key_file.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() 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, ` prebuilt_apex { name: "myapex", arch: { arm64: { src: "myapex-arm64.apex", }, arm: { src: "myapex-arm.apex", }, }, key: "myapex.key" } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", product_specific: true, } `) prebuilt := ctx.ModuleForTests("myapex", "android_common").Module().(*Prebuilt) expectedInput := "myapex-arm64.apex" if prebuilt.inputApex.String() != expectedInput { t.Errorf("inputApex invalid. expected: %q, actual: %q", expectedInput, prebuilt.inputApex.String()) } // Check if the key module is added as a required module. buf := &bytes.Buffer{} prebuilt.AndroidMk().Extra[0](buf, nil) found := false scanner := bufio.NewScanner(bytes.NewReader(buf.Bytes())) expected := "myapex.key" for scanner.Scan() { line := scanner.Text() tok := strings.Split(line, " := ") if tok[0] == "LOCAL_REQUIRED_MODULES" { found = true if tok[1] != "myapex.key" { t.Errorf("Unexpected LOCAL_REQUIRED_MODULES '%s', expected '%s'", tok[1], expected) } } } if !found { t.Errorf("Couldn't find a LOCAL_REQUIRED_MODULES entry") } }