56a8321c21
A global variant was used to store the global mapping between modules and APEXes. Replace it with storing pointers to APEX contents inside each module so that they can query the contents of any APEXes they belong to. Bug: 146393795 Test: all Soong tests Test: single line change to build.ninja host install dependency ordering Test: no Android-${TARGET_PRODUCT}.mk, make_vars-${TARGET_PRODUCT}.mk or late-${TARGET_PRODUCT}.mk Change-Id: Id2d7b73ea27f8c3b41d30820bdd86b65c539bfa4
6248 lines
166 KiB
Go
6248 lines
166 KiB
Go
// 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 (
|
|
"io/ioutil"
|
|
"os"
|
|
"path"
|
|
"reflect"
|
|
"regexp"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/google/blueprint/proptools"
|
|
|
|
"android/soong/android"
|
|
"android/soong/bpf"
|
|
"android/soong/cc"
|
|
"android/soong/dexpreopt"
|
|
prebuilt_etc "android/soong/etc"
|
|
"android/soong/java"
|
|
"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, " ") {
|
|
if len(n) > 0 {
|
|
ns = append(ns, n)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func testApexError(t *testing.T, pattern, bp string, handlers ...testCustomizer) {
|
|
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)
|
|
}
|
|
|
|
func testApex(t *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) {
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
func withTargets(targets map[android.OsType][]android.Target) testCustomizer {
|
|
return func(fs map[string][]byte, config android.Config) {
|
|
for k, v := range targets {
|
|
config.Targets[k] = v
|
|
}
|
|
}
|
|
}
|
|
|
|
// withNativeBridgeTargets sets configuration with targets including:
|
|
// - X86_64 (primary)
|
|
// - X86 (secondary)
|
|
// - Arm64 on X86_64 (native bridge)
|
|
// - Arm on X86 (native bridge)
|
|
func withNativeBridgeEnabled(_ map[string][]byte, 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 withManifestPackageNameOverrides(specs []string) testCustomizer {
|
|
return func(fs map[string][]byte, config android.Config) {
|
|
config.TestProductVariables.ManifestPackageNameOverrides = specs
|
|
}
|
|
}
|
|
|
|
func withBinder32bit(_ map[string][]byte, config android.Config) {
|
|
config.TestProductVariables.Binder32bit = proptools.BoolPtr(true)
|
|
}
|
|
|
|
func withUnbundledBuild(_ map[string][]byte, config android.Config) {
|
|
config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
|
|
}
|
|
|
|
func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) {
|
|
bp = bp + `
|
|
filegroup {
|
|
name: "myapex-file_contexts",
|
|
srcs: [
|
|
"system/sepolicy/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,
|
|
"mylib.cpp": nil,
|
|
"mylib_common.cpp": nil,
|
|
"mytest.cpp": nil,
|
|
"mytest1.cpp": nil,
|
|
"mytest2.cpp": nil,
|
|
"mytest3.cpp": nil,
|
|
"myprebuilt": nil,
|
|
"my_include": nil,
|
|
"foo/bar/MyClass.java": nil,
|
|
"prebuilt.jar": nil,
|
|
"prebuilt.so": 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,
|
|
"custom_notice_for_static_lib": nil,
|
|
"testkey2.avbpubkey": nil,
|
|
"testkey2.pem": nil,
|
|
"myapex-arm64.apex": nil,
|
|
"myapex-arm.apex": nil,
|
|
"myapex.apks": nil,
|
|
"frameworks/base/api/current.txt": nil,
|
|
"framework/aidl/a.aidl": nil,
|
|
"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_version_active_codenames = []string{"Q"}
|
|
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.PreArchMutators(android.RegisterComponentsMutator)
|
|
ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
|
|
|
|
android.RegisterPrebuiltMutators(ctx)
|
|
|
|
// Register these after the prebuilt mutators have been registered to match what
|
|
// happens at runtime.
|
|
ctx.PreArchMutators(android.RegisterVisibilityRuleGatherer)
|
|
ctx.PostDepsMutators(android.RegisterVisibilityRuleEnforcer)
|
|
|
|
cc.RegisterRequiredBuildComponentsForTest(ctx)
|
|
|
|
ctx.RegisterModuleType("cc_test", cc.TestFactory)
|
|
ctx.RegisterModuleType("vndk_prebuilt_shared", cc.VndkPrebuiltSharedFactory)
|
|
ctx.RegisterModuleType("vndk_libraries_txt", cc.VndkLibrariesTxtFactory)
|
|
prebuilt_etc.RegisterPrebuiltEtcBuildComponents(ctx)
|
|
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)
|
|
|
|
ctx.Register(config)
|
|
|
|
return ctx, config
|
|
}
|
|
|
|
func setUp() {
|
|
var err error
|
|
buildDir, err = ioutil.TempDir("", "soong_apex_test")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func tearDown() {
|
|
_ = os.RemoveAll(buildDir)
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
}
|
|
|
|
// ensure that 'result' contains 'expected'
|
|
func ensureContains(t *testing.T, result string, expected string) {
|
|
t.Helper()
|
|
if !strings.Contains(result, expected) {
|
|
t.Errorf("%q is not found in %q", expected, result)
|
|
}
|
|
}
|
|
|
|
// 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()
|
|
if strings.Contains(result, notExpected) {
|
|
t.Errorf("%q is found in %q", notExpected, result)
|
|
}
|
|
}
|
|
|
|
func ensureMatches(t *testing.T, result string, expectedRex string) {
|
|
ok, err := regexp.MatchString(expectedRex, result)
|
|
if err != nil {
|
|
t.Fatalf("regexp failure trying to match %s against `%s` expression: %s", result, expectedRex, err)
|
|
return
|
|
}
|
|
if !ok {
|
|
t.Errorf("%s does not match regular expession %s", result, expectedRex)
|
|
}
|
|
}
|
|
|
|
func ensureListContains(t *testing.T, result []string, expected string) {
|
|
t.Helper()
|
|
if !android.InList(expected, result) {
|
|
t.Errorf("%q is not found in %v", expected, result)
|
|
}
|
|
}
|
|
|
|
func ensureListNotContains(t *testing.T, result []string, notExpected string) {
|
|
t.Helper()
|
|
if android.InList(notExpected, result) {
|
|
t.Errorf("%q is found in %v", notExpected, result)
|
|
}
|
|
}
|
|
|
|
func ensureListEmpty(t *testing.T, result []string) {
|
|
t.Helper()
|
|
if len(result) > 0 {
|
|
t.Errorf("%q is expected to be empty", result)
|
|
}
|
|
}
|
|
|
|
// Minimal test
|
|
func TestBasicApex(t *testing.T) {
|
|
ctx, config := testApex(t, `
|
|
apex_defaults {
|
|
name: "myapex-defaults",
|
|
manifest: ":myapex.manifest",
|
|
androidManifest: ":myapex.androidmanifest",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["mylib"],
|
|
multilib: {
|
|
both: {
|
|
binaries: ["foo",],
|
|
}
|
|
},
|
|
java_libs: [
|
|
"myjar",
|
|
"myjar_dex",
|
|
],
|
|
}
|
|
|
|
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",
|
|
// TODO: remove //apex_available:platform
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"myapex",
|
|
],
|
|
}
|
|
|
|
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",
|
|
apex_available: [ "myapex", "com.android.gki.*" ],
|
|
}
|
|
|
|
apex {
|
|
name: "com.android.gki.fake",
|
|
binaries: ["foo"],
|
|
key: "myapex.key",
|
|
file_contexts: ":myapex-file_contexts",
|
|
}
|
|
|
|
cc_library_shared {
|
|
name: "mylib2",
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
notice: "custom_notice",
|
|
static_libs: ["libstatic"],
|
|
// TODO: remove //apex_available:platform
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"myapex",
|
|
],
|
|
}
|
|
|
|
cc_prebuilt_library_shared {
|
|
name: "mylib2",
|
|
srcs: ["prebuilt.so"],
|
|
// TODO: remove //apex_available:platform
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"myapex",
|
|
],
|
|
}
|
|
|
|
cc_library_static {
|
|
name: "libstatic",
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
notice: "custom_notice_for_static_lib",
|
|
// TODO: remove //apex_available:platform
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"myapex",
|
|
],
|
|
}
|
|
|
|
java_library {
|
|
name: "myjar",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
stem: "myjar_stem",
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
static_libs: ["myotherjar"],
|
|
libs: ["mysharedjar"],
|
|
// TODO: remove //apex_available:platform
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"myapex",
|
|
],
|
|
}
|
|
|
|
dex_import {
|
|
name: "myjar_dex",
|
|
jars: ["prebuilt.jar"],
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"myapex",
|
|
],
|
|
}
|
|
|
|
java_library {
|
|
name: "myotherjar",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
// TODO: remove //apex_available:platform
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"myapex",
|
|
],
|
|
}
|
|
|
|
java_library {
|
|
name: "mysharedjar",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
}
|
|
`)
|
|
|
|
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
|
|
|
|
// Make sure that Android.mk is created
|
|
ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
|
|
data := android.AndroidMkDataForTest(t, config, "", ab)
|
|
var builder strings.Builder
|
|
data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data)
|
|
|
|
androidMk := builder.String()
|
|
ensureContains(t, androidMk, "LOCAL_MODULE := mylib.myapex\n")
|
|
ensureNotContains(t, androidMk, "LOCAL_MODULE := mylib.com.android.myapex\n")
|
|
|
|
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")
|
|
|
|
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_shared_apex10000")
|
|
ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_apex10000")
|
|
ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_apex10000")
|
|
|
|
// Ensure that apex variant is created for the indirect dep
|
|
ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000")
|
|
ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common_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")
|
|
// .. but not for java libs
|
|
ensureNotContains(t, copyCmds, "image.apex/javalib/myotherjar.jar")
|
|
ensureNotContains(t, copyCmds, "image.apex/javalib/msharedjar.jar")
|
|
|
|
// Ensure that the platform variant ends with _shared or _common
|
|
ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared")
|
|
ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared")
|
|
ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common")
|
|
ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common")
|
|
ensureListContains(t, ctx.ModuleVariantsForTests("mysharedjar"), "android_common")
|
|
|
|
// Ensure that dynamic dependency to java libs are not included
|
|
ensureListNotContains(t, ctx.ModuleVariantsForTests("mysharedjar"), "android_common_myapex")
|
|
|
|
// 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 -sfn 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)
|
|
}
|
|
|
|
mergeNoticesRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("mergeNoticesRule")
|
|
noticeInputs := mergeNoticesRule.Inputs.Strings()
|
|
if len(noticeInputs) != 3 {
|
|
t.Errorf("number of input notice files: expected = 3, actual = %q", len(noticeInputs))
|
|
}
|
|
ensureListContains(t, noticeInputs, "NOTICE")
|
|
ensureListContains(t, noticeInputs, "custom_notice")
|
|
ensureListContains(t, noticeInputs, "custom_notice_for_static_lib")
|
|
|
|
fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
|
|
ensureListContains(t, fullDepsInfo, " myjar(minSdkVersion:(no version)) <- myapex")
|
|
ensureListContains(t, fullDepsInfo, " mylib(minSdkVersion:(no version)) <- myapex")
|
|
ensureListContains(t, fullDepsInfo, " mylib2(minSdkVersion:(no version)) <- mylib")
|
|
ensureListContains(t, fullDepsInfo, " myotherjar(minSdkVersion:(no version)) <- myjar")
|
|
ensureListContains(t, fullDepsInfo, " mysharedjar(minSdkVersion:(no version)) (external) <- myjar")
|
|
|
|
flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("depsinfo/flatlist.txt").Args["content"], "\\n")
|
|
ensureListContains(t, flatDepsInfo, "myjar(minSdkVersion:(no version))")
|
|
ensureListContains(t, flatDepsInfo, "mylib(minSdkVersion:(no version))")
|
|
ensureListContains(t, flatDepsInfo, "mylib2(minSdkVersion:(no version))")
|
|
ensureListContains(t, flatDepsInfo, "myotherjar(minSdkVersion:(no version))")
|
|
ensureListContains(t, flatDepsInfo, "mysharedjar(minSdkVersion:(no version)) (external)")
|
|
}
|
|
|
|
func TestDefaults(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex_defaults {
|
|
name: "myapex-defaults",
|
|
key: "myapex.key",
|
|
prebuilts: ["myetc"],
|
|
native_shared_libs: ["mylib"],
|
|
java_libs: ["myjar"],
|
|
apps: ["AppFoo"],
|
|
rros: ["rro"],
|
|
bpfs: ["bpf"],
|
|
}
|
|
|
|
prebuilt_etc {
|
|
name: "myetc",
|
|
src: "myprebuilt",
|
|
}
|
|
|
|
apex {
|
|
name: "myapex",
|
|
defaults: ["myapex-defaults"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "mylib",
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
java_library {
|
|
name: "myjar",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
android_app {
|
|
name: "AppFoo",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
runtime_resource_overlay {
|
|
name: "rro",
|
|
theme: "blue",
|
|
}
|
|
|
|
bpf {
|
|
name: "bpf",
|
|
srcs: ["bpf.c", "bpf2.c"],
|
|
}
|
|
|
|
`)
|
|
ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
|
|
"etc/myetc",
|
|
"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, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
`)
|
|
|
|
module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
|
|
args := module.Rule("apexRule").Args
|
|
if manifest := args["manifest"]; manifest != module.Output("apex_manifest.pb").Output.String() {
|
|
t.Error("manifest should be apex_manifest.pb, but " + manifest)
|
|
}
|
|
}
|
|
|
|
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",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
cc_library {
|
|
name: "mylib2",
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
`)
|
|
|
|
zipApexRule := ctx.ModuleForTests("myapex", "android_common_myapex_zip").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_shared_apex10000")
|
|
|
|
// Ensure that APEX variant is created for the indirect dep
|
|
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")
|
|
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",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
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"],
|
|
},
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
cc_library {
|
|
name: "mylib4",
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
`)
|
|
|
|
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_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")
|
|
// ... 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_apex10000/mylib3.so")
|
|
// .. and not linking to the stubs variant of mylib3
|
|
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"])
|
|
|
|
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 version 29 stubs for mylib2
|
|
ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_29/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_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_29").Rule("genStubSrc").Args["flags"])
|
|
|
|
ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
|
|
"lib64/mylib.so",
|
|
"lib64/mylib3.so",
|
|
"lib64/mylib4.so",
|
|
})
|
|
}
|
|
|
|
func TestApexWithExplicitStubsDependency(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex2",
|
|
key: "myapex2.key",
|
|
native_shared_libs: ["mylib"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex2.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "mylib",
|
|
srcs: ["mylib.cpp"],
|
|
shared_libs: ["libfoo#10"],
|
|
static_libs: ["libbaz"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex2" ],
|
|
}
|
|
|
|
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",
|
|
}
|
|
|
|
cc_library_static {
|
|
name: "libbaz",
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex2" ],
|
|
}
|
|
|
|
`)
|
|
|
|
apexRule := ctx.ModuleForTests("myapex2", "android_common_myapex2_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/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_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")
|
|
// ... and not linking to the non-stub (impl) variant of libfoo
|
|
ensureNotContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared/libfoo.so")
|
|
|
|
libFooStubsLdFlags := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared_10").Rule("ld").Args["libFlags"]
|
|
|
|
// Ensure that libfoo stubs is not linking to libbar (since it is a stubs)
|
|
ensureNotContains(t, libFooStubsLdFlags, "libbar.so")
|
|
|
|
fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
|
|
ensureListContains(t, fullDepsInfo, " mylib(minSdkVersion:(no version)) <- myapex2")
|
|
ensureListContains(t, fullDepsInfo, " libbaz(minSdkVersion:(no version)) <- mylib")
|
|
ensureListContains(t, fullDepsInfo, " libfoo(minSdkVersion:(no version)) (external) <- mylib")
|
|
|
|
flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("depsinfo/flatlist.txt").Args["content"], "\\n")
|
|
ensureListContains(t, flatDepsInfo, "mylib(minSdkVersion:(no version))")
|
|
ensureListContains(t, flatDepsInfo, "libbaz(minSdkVersion:(no version))")
|
|
ensureListContains(t, flatDepsInfo, "libfoo(minSdkVersion:(no version)) (external)")
|
|
}
|
|
|
|
func TestApexWithRuntimeLibsDependency(t *testing.T) {
|
|
/*
|
|
myapex
|
|
|
|
|
v (runtime_libs)
|
|
mylib ------+------> libfoo [provides stub]
|
|
|
|
|
`------> libbar
|
|
*/
|
|
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"],
|
|
runtime_libs: ["libfoo", "libbar"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
cc_library {
|
|
name: "libfoo",
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
stubs: {
|
|
versions: ["10", "20", "30"],
|
|
},
|
|
}
|
|
|
|
cc_library {
|
|
name: "libbar",
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
`)
|
|
|
|
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/libfoo.so")
|
|
|
|
// Ensure that runtime_libs dep in included
|
|
ensureContains(t, copyCmds, "image.apex/lib64/libbar.so")
|
|
|
|
apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
|
|
ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
|
|
ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.so")
|
|
|
|
}
|
|
|
|
func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) {
|
|
ctx, _ := testApex(t, "", func(fs map[string][]byte, config android.Config) {
|
|
bp := `
|
|
apex {
|
|
name: "com.android.runtime",
|
|
key: "com.android.runtime.key",
|
|
native_shared_libs: ["libc"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "com.android.runtime.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
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,
|
|
},
|
|
}
|
|
`
|
|
// override bp to use hard-coded names: com.android.runtime and libc
|
|
fs["Android.bp"] = []byte(bp)
|
|
fs["system/sepolicy/apex/com.android.runtime-file_contexts"] = nil
|
|
})
|
|
|
|
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) {
|
|
ctx, _ := testApex(t, "", func(fs map[string][]byte, config android.Config) {
|
|
bp := `
|
|
apex {
|
|
name: "com.android.runtime",
|
|
key: "com.android.runtime.key",
|
|
native_shared_libs: ["libc"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "com.android.runtime.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
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,
|
|
},
|
|
}
|
|
`
|
|
// override bp to use hard-coded names: com.android.runtime and libc
|
|
fs["Android.bp"] = []byte(bp)
|
|
fs["system/sepolicy/apex/com.android.runtime-file_contexts"] = nil
|
|
|
|
config.TestProductVariables.SanitizeDevice = []string{"hwaddress"}
|
|
})
|
|
|
|
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: "",
|
|
apexVariant: "apex10000",
|
|
shouldLink: "30",
|
|
shouldNotLink: []string{"29"},
|
|
},
|
|
{
|
|
name: "should link to llndk#29",
|
|
minSdkVersion: "min_sdk_version: \"29\",",
|
|
apexVariant: "apex29",
|
|
shouldLink: "29",
|
|
shouldNotLink: []string{"30"},
|
|
},
|
|
}
|
|
for _, tc := range testcases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
use_vendor: true,
|
|
native_shared_libs: ["mylib"],
|
|
`+tc.minSdkVersion+`
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "mylib",
|
|
srcs: ["mylib.cpp"],
|
|
vendor_available: true,
|
|
shared_libs: ["libbar"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
min_sdk_version: "29",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libbar",
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
stubs: { versions: ["29","30"] },
|
|
}
|
|
|
|
llndk_library {
|
|
name: "libbar",
|
|
symbol_file: "",
|
|
}
|
|
`, func(fs map[string][]byte, config android.Config) {
|
|
setUseVendorAllowListForTest(config, []string{"myapex"})
|
|
}, withUnbundledBuild)
|
|
|
|
// Ensure that LLNDK dep is not included
|
|
ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
|
|
"lib64/mylib.so",
|
|
})
|
|
|
|
// Ensure that LLNDK dep is required
|
|
apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
|
|
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_"+tc.apexVariant).Rule("ld").Args["libFlags"]
|
|
ensureContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_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")
|
|
}
|
|
|
|
mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_"+tc.apexVariant).Rule("cc").Args["cFlags"]
|
|
ensureContains(t, mylibCFlags, "__LIBBAR_API__="+tc.shouldLink)
|
|
})
|
|
}
|
|
}
|
|
|
|
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",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
cc_library_shared {
|
|
name: "mylib_shared",
|
|
srcs: ["mylib.cpp"],
|
|
shared_libs: ["libdl#27"],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
cc_library {
|
|
name: "libBootstrap",
|
|
srcs: ["mylib.cpp"],
|
|
stl: "none",
|
|
bootstrap: true,
|
|
}
|
|
`)
|
|
|
|
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").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_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")
|
|
// ... 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")
|
|
|
|
// For dependency to libm
|
|
// Ensure that mylib is linking with the non-stub (impl) variant
|
|
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
|
|
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_shared_27/libdl.so")
|
|
// ... and not linking to the other versions of stubs
|
|
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_apex10000/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_shared").Rule("ld").Args["libFlags"]
|
|
ensureContains(t, libFlags, "libc/android_arm64_armv8-a_shared/libc.so")
|
|
ensureContains(t, libFlags, "libm/android_arm64_armv8-a_shared/libm.so")
|
|
ensureContains(t, libFlags, "libdl/android_arm64_armv8-a_shared/libdl.so")
|
|
}
|
|
|
|
func TestApexMinSdkVersion_NativeModulesShouldBeBuiltAgainstStubs(t *testing.T) {
|
|
// there are three links between liba --> libz
|
|
// 1) myapex -> libx -> liba -> libz : this should be #29 link, but fallback to #28
|
|
// 2) otherapex -> liby -> liba -> libz : this should be #30 link
|
|
// 3) (platform) -> liba -> libz : this should be non-stub link
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["libx"],
|
|
min_sdk_version: "29",
|
|
}
|
|
|
|
apex {
|
|
name: "otherapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["liby"],
|
|
min_sdk_version: "30",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libx",
|
|
shared_libs: ["liba"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
min_sdk_version: "29",
|
|
}
|
|
|
|
cc_library {
|
|
name: "liby",
|
|
shared_libs: ["liba"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "otherapex" ],
|
|
min_sdk_version: "29",
|
|
}
|
|
|
|
cc_library {
|
|
name: "liba",
|
|
shared_libs: ["libz"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [
|
|
"//apex_available:anyapex",
|
|
"//apex_available:platform",
|
|
],
|
|
min_sdk_version: "29",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libz",
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
stubs: {
|
|
versions: ["28", "30"],
|
|
},
|
|
}
|
|
`)
|
|
|
|
expectLink := func(from, from_variant, to, to_variant string) {
|
|
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) {
|
|
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")
|
|
}
|
|
// platform liba is linked to non-stub version
|
|
expectLink("liba", "shared", "libz", "shared")
|
|
// liba in myapex is linked to #28
|
|
expectLink("liba", "shared_apex29", "libz", "shared_28")
|
|
expectNoLink("liba", "shared_apex29", "libz", "shared_30")
|
|
expectNoLink("liba", "shared_apex29", "libz", "shared")
|
|
// liba in otherapex is linked to #30
|
|
expectLink("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, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["libx"],
|
|
min_sdk_version: "R",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libx",
|
|
shared_libs: ["libz"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
min_sdk_version: "R",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libz",
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
stubs: {
|
|
versions: ["29", "R"],
|
|
},
|
|
}
|
|
`, func(fs map[string][]byte, config android.Config) {
|
|
config.TestProductVariables.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"]
|
|
ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
|
|
}
|
|
expectNoLink := func(from, from_variant, to, to_variant string) {
|
|
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_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"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libx",
|
|
shared_libs: ["libz"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
cc_library {
|
|
name: "libz",
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
stubs: {
|
|
versions: ["1", "2"],
|
|
},
|
|
}
|
|
`)
|
|
|
|
expectLink := func(from, from_variant, to, to_variant string) {
|
|
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) {
|
|
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_apex10000", "libz", "shared_2")
|
|
expectNoLink("libx", "shared_apex10000", "libz", "shared_1")
|
|
expectNoLink("libx", "shared_apex10000", "libz", "shared")
|
|
}
|
|
|
|
func TestPlatformUsesLatestStubsFromApexes(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["libx"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libx",
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
stubs: {
|
|
versions: ["1", "2"],
|
|
},
|
|
}
|
|
|
|
cc_library {
|
|
name: "libz",
|
|
shared_libs: ["libx"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
}
|
|
`)
|
|
|
|
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")
|
|
expectNoLink("libz", "shared", "libz", "shared_1")
|
|
expectNoLink("libz", "shared", "libz", "shared")
|
|
}
|
|
|
|
func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["libx"],
|
|
min_sdk_version: "29",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libx",
|
|
shared_libs: ["libbar"],
|
|
apex_available: [ "myapex" ],
|
|
min_sdk_version: "29",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libbar",
|
|
stubs: {
|
|
versions: ["29", "30"],
|
|
},
|
|
}
|
|
`, func(fs map[string][]byte, config android.Config) {
|
|
config.TestProductVariables.SanitizeDevice = []string{"hwaddress"}
|
|
})
|
|
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_apex29", "libbar", "shared_30")
|
|
}
|
|
|
|
func TestQTargetApexUsesStaticUnwinder(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["libx"],
|
|
min_sdk_version: "29",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
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_apex29").Module().(*cc.Module)
|
|
ensureListContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped")
|
|
// 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")
|
|
}
|
|
|
|
func TestApexMinSdkVersion_ErrorIfIncompatibleStubs(t *testing.T) {
|
|
testApexError(t, `"libz" .*: not found a version\(<=29\)`, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["libx"],
|
|
min_sdk_version: "29",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libx",
|
|
shared_libs: ["libz"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
min_sdk_version: "29",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libz",
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
stubs: {
|
|
versions: ["30"],
|
|
},
|
|
}
|
|
`)
|
|
}
|
|
|
|
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: ["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"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [
|
|
"myapex",
|
|
],
|
|
min_sdk_version: "30",
|
|
}
|
|
`)
|
|
}
|
|
|
|
func TestApexMinSdkVersion_Okay(t *testing.T) {
|
|
testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["libfoo"],
|
|
java_libs: ["libbar"],
|
|
min_sdk_version: "29",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
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"],
|
|
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",
|
|
}
|
|
`)
|
|
}
|
|
|
|
func TestJavaStableSdkVersion(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
expectedError string
|
|
bp string
|
|
}{
|
|
{
|
|
name: "Non-updatable apex with non-stable dep",
|
|
bp: `
|
|
apex {
|
|
name: "myapex",
|
|
java_libs: ["myjar"],
|
|
key: "myapex.key",
|
|
}
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
java_library {
|
|
name: "myjar",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
sdk_version: "core_platform",
|
|
apex_available: ["myapex"],
|
|
}
|
|
`,
|
|
},
|
|
{
|
|
name: "Updatable apex with stable dep",
|
|
bp: `
|
|
apex {
|
|
name: "myapex",
|
|
java_libs: ["myjar"],
|
|
key: "myapex.key",
|
|
updatable: true,
|
|
min_sdk_version: "29",
|
|
}
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
java_library {
|
|
name: "myjar",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
sdk_version: "current",
|
|
apex_available: ["myapex"],
|
|
min_sdk_version: "29",
|
|
}
|
|
`,
|
|
},
|
|
{
|
|
name: "Updatable apex with non-stable dep",
|
|
expectedError: "cannot depend on \"myjar\"",
|
|
bp: `
|
|
apex {
|
|
name: "myapex",
|
|
java_libs: ["myjar"],
|
|
key: "myapex.key",
|
|
updatable: true,
|
|
}
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
java_library {
|
|
name: "myjar",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
sdk_version: "core_platform",
|
|
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.",
|
|
bp: `
|
|
apex {
|
|
name: "myapex",
|
|
java_libs: ["myjar"],
|
|
key: "myapex.key",
|
|
updatable: true,
|
|
}
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
java_library {
|
|
name: "myjar",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
sdk_version: "current",
|
|
apex_available: ["myapex"],
|
|
static_libs: ["transitive-jar"],
|
|
}
|
|
java_library {
|
|
name: "transitive-jar",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
sdk_version: "core_platform",
|
|
apex_available: ["myapex"],
|
|
}
|
|
`,
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if test.expectedError == "" {
|
|
testApex(t, test.bp)
|
|
} else {
|
|
testApexError(t, test.expectedError, test.bp)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
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#29
|
|
// 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_29")
|
|
expectLink("mylib", "shared_apex30", "mylib2", "shared_apex30")
|
|
}
|
|
|
|
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",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
cc_binary {
|
|
name: "mybin",
|
|
srcs: ["mylib.cpp"],
|
|
relative_install_path: "foo/bar",
|
|
system_shared_libs: [],
|
|
static_executable: true,
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
`)
|
|
|
|
generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").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 TestFilesInSubDirWhenNativeBridgeEnabled(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
multilib: {
|
|
both: {
|
|
native_shared_libs: ["mylib"],
|
|
binaries: ["mybin"],
|
|
},
|
|
},
|
|
compile_multilib: "both",
|
|
native_bridge_supported: true,
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "mylib",
|
|
relative_install_path: "foo/bar",
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
native_bridge_supported: true,
|
|
}
|
|
|
|
cc_binary {
|
|
name: "mybin",
|
|
relative_install_path: "foo/bar",
|
|
system_shared_libs: [],
|
|
static_executable: true,
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
native_bridge_supported: true,
|
|
compile_multilib: "both", // default is "first" for binary
|
|
multilib: {
|
|
lib64: {
|
|
suffix: "64",
|
|
},
|
|
},
|
|
}
|
|
`, 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",
|
|
})
|
|
}
|
|
|
|
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",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
cc_library {
|
|
name: "mylib2",
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
vendor_available: true,
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
`, func(fs map[string][]byte, config android.Config) {
|
|
setUseVendorAllowListForTest(config, []string{"myapex"})
|
|
})
|
|
|
|
inputsList := []string{}
|
|
for _, i := range ctx.ModuleForTests("myapex", "android_common_myapex_image").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_vendor.VER_arm64_armv8-a_shared_apex10000/mylib.so")
|
|
ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_apex10000/mylib2.so")
|
|
|
|
// ensure that the apex does not include core variants
|
|
ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_apex10000/mylib.so")
|
|
ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_apex10000/mylib2.so")
|
|
}
|
|
|
|
func TestUseVendorNotAllowedForSystemApexes(t *testing.T) {
|
|
testApexError(t, `module "myapex" .*: use_vendor: not allowed`, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
use_vendor: true,
|
|
}
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
`, func(fs map[string][]byte, config android.Config) {
|
|
setUseVendorAllowListForTest(config, []string{""})
|
|
})
|
|
// no error with allow list
|
|
testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
use_vendor: true,
|
|
}
|
|
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"})
|
|
})
|
|
}
|
|
|
|
func TestUseVendorFailsIfNotVendorAvailable(t *testing.T) {
|
|
testApexError(t, `dependency "mylib" of "myapex" missing variant:\n.*image:vendor`, `
|
|
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"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
}
|
|
`)
|
|
}
|
|
|
|
func TestVendorApex(t *testing.T) {
|
|
ctx, config := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
binaries: ["mybin"],
|
|
vendor: true,
|
|
}
|
|
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,
|
|
}
|
|
`)
|
|
|
|
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",
|
|
})
|
|
|
|
apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
|
|
data := android.AndroidMkDataForTest(t, config, "", apexBundle)
|
|
name := apexBundle.BaseModuleName()
|
|
prefix := "TARGET_"
|
|
var builder strings.Builder
|
|
data.Custom(&builder, name, prefix, "", data)
|
|
androidMk := builder.String()
|
|
ensureContains(t, androidMk, `LOCAL_MODULE_PATH := /tmp/target/product/test_device/vendor/apex`)
|
|
|
|
apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
|
|
requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"])
|
|
ensureListNotContains(t, requireNativeLibs, ":vndk")
|
|
}
|
|
|
|
func TestVendorApex_use_vndk_as_stable(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
binaries: ["mybin"],
|
|
vendor: true,
|
|
use_vndk_as_stable: true,
|
|
}
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
cc_binary {
|
|
name: "mybin",
|
|
vendor: true,
|
|
shared_libs: ["libvndk", "libvendor"],
|
|
}
|
|
cc_library {
|
|
name: "libvndk",
|
|
vndk: {
|
|
enabled: true,
|
|
},
|
|
vendor_available: true,
|
|
}
|
|
cc_library {
|
|
name: "libvendor",
|
|
vendor: true,
|
|
}
|
|
`)
|
|
|
|
vendorVariant := "android_vendor.VER_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, buildDir+"/.intermediates/libvndk/"+vendorVariant+"_shared/libvndk.so")
|
|
ensureListContains(t, libs, buildDir+"/.intermediates/libc++/"+vendorVariant+"_shared/libc++.so")
|
|
// non-stable Vendor libs as APEX variants
|
|
ensureListContains(t, libs, buildDir+"/.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",
|
|
})
|
|
|
|
apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
|
|
requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"])
|
|
ensureListContains(t, requireNativeLibs, ":vndk")
|
|
}
|
|
|
|
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"],
|
|
`+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_UseVendorRequired(t *testing.T) {
|
|
ctx, config := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
use_vendor: true,
|
|
native_shared_libs: ["mylib"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "mylib",
|
|
vendor_available: true,
|
|
apex_available: ["myapex"],
|
|
}
|
|
`, func(fs map[string][]byte, config android.Config) {
|
|
setUseVendorAllowListForTest(config, []string{"myapex"})
|
|
})
|
|
|
|
apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
|
|
data := android.AndroidMkDataForTest(t, config, "", 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 libm libdl\n")
|
|
}
|
|
|
|
func TestAndroidMk_VendorApexRequired(t *testing.T) {
|
|
ctx, config := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
vendor: true,
|
|
native_shared_libs: ["mylib"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "mylib",
|
|
vendor_available: true,
|
|
}
|
|
`)
|
|
|
|
apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
|
|
data := android.AndroidMkDataForTest(t, config, "", 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, config := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
vintf_fragments: ["fragment.xml"],
|
|
init_rc: ["init.rc"],
|
|
}
|
|
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, config, "", apexBundle)
|
|
name := apexBundle.BaseModuleName()
|
|
prefix := "TARGET_"
|
|
var builder strings.Builder
|
|
data.Custom(&builder, name, prefix, "", data)
|
|
androidMk := builder.String()
|
|
ensureContains(t, androidMk, "LOCAL_VINTF_FRAGMENTS := fragment.xml\n")
|
|
ensureContains(t, androidMk, "LOCAL_INIT_RC := init.rc\n")
|
|
}
|
|
|
|
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"],
|
|
},
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"myapex",
|
|
],
|
|
}
|
|
|
|
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").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_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"],
|
|
file_contexts: ":myapex-file_contexts",
|
|
}
|
|
|
|
cc_library {
|
|
name: "mylib",
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex_keytest" ],
|
|
}
|
|
|
|
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_image").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 TestCertificate(t *testing.T) {
|
|
t.Run("if unspecified, it defaults to DefaultAppCertificate", func(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
}
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}`)
|
|
rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("signapk")
|
|
expected := "vendor/foo/devkeys/test.x509.pem vendor/foo/devkeys/test.pk8"
|
|
if actual := rule.Args["certificates"]; actual != expected {
|
|
t.Errorf("certificates should be %q, not %q", expected, actual)
|
|
}
|
|
})
|
|
t.Run("override when unspecified", func(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex_keytest",
|
|
key: "myapex.key",
|
|
file_contexts: ":myapex-file_contexts",
|
|
}
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
android_app_certificate {
|
|
name: "myapex.certificate.override",
|
|
certificate: "testkey.override",
|
|
}`)
|
|
rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk")
|
|
expected := "testkey.override.x509.pem testkey.override.pk8"
|
|
if actual := rule.Args["certificates"]; actual != expected {
|
|
t.Errorf("certificates should be %q, not %q", expected, actual)
|
|
}
|
|
})
|
|
t.Run("if specified as :module, it respects the prop", func(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
certificate: ":myapex.certificate",
|
|
}
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
android_app_certificate {
|
|
name: "myapex.certificate",
|
|
certificate: "testkey",
|
|
}`)
|
|
rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("signapk")
|
|
expected := "testkey.x509.pem testkey.pk8"
|
|
if actual := rule.Args["certificates"]; actual != expected {
|
|
t.Errorf("certificates should be %q, not %q", expected, actual)
|
|
}
|
|
})
|
|
t.Run("override when specifiec as <:module>", func(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex_keytest",
|
|
key: "myapex.key",
|
|
file_contexts: ":myapex-file_contexts",
|
|
certificate: ":myapex.certificate",
|
|
}
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
android_app_certificate {
|
|
name: "myapex.certificate.override",
|
|
certificate: "testkey.override",
|
|
}`)
|
|
rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk")
|
|
expected := "testkey.override.x509.pem testkey.override.pk8"
|
|
if actual := rule.Args["certificates"]; actual != expected {
|
|
t.Errorf("certificates should be %q, not %q", expected, actual)
|
|
}
|
|
})
|
|
t.Run("if specified as name, finds it from DefaultDevKeyDir", func(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
certificate: "testkey",
|
|
}
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}`)
|
|
rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("signapk")
|
|
expected := "vendor/foo/devkeys/testkey.x509.pem vendor/foo/devkeys/testkey.pk8"
|
|
if actual := rule.Args["certificates"]; actual != expected {
|
|
t.Errorf("certificates should be %q, not %q", expected, actual)
|
|
}
|
|
})
|
|
t.Run("override when specified as <name>", func(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex_keytest",
|
|
key: "myapex.key",
|
|
file_contexts: ":myapex-file_contexts",
|
|
certificate: "testkey",
|
|
}
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
android_app_certificate {
|
|
name: "myapex.certificate.override",
|
|
certificate: "testkey.override",
|
|
}`)
|
|
rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk")
|
|
expected := "testkey.override.x509.pem testkey.override.pk8"
|
|
if actual := rule.Args["certificates"]; actual != expected {
|
|
t.Errorf("certificates should be %q, not %q", expected, actual)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMacro(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["mylib", "mylib2"],
|
|
}
|
|
|
|
apex {
|
|
name: "otherapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["mylib", "mylib2"],
|
|
min_sdk_version: "29",
|
|
}
|
|
|
|
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",
|
|
apex_available: [
|
|
"myapex",
|
|
"otherapex",
|
|
],
|
|
recovery_available: true,
|
|
min_sdk_version: "29",
|
|
}
|
|
cc_library {
|
|
name: "mylib2",
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [
|
|
"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__")
|
|
|
|
// APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined
|
|
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")
|
|
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_apex29").Rule("cc").Args["cFlags"]
|
|
ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
|
|
ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=29")
|
|
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
|
|
|
|
// 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_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_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"]
|
|
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
|
|
|
|
// 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__")
|
|
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__")
|
|
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
|
|
|
|
// recovery variant does not set __ANDROID_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__")
|
|
}
|
|
|
|
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",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
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"],
|
|
},
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
cc_library {
|
|
name: "otherlib",
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
shared_libs: ["mylib"],
|
|
}
|
|
`)
|
|
|
|
cFlags := ctx.ModuleForTests("otherlib", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
|
|
|
|
// Ensure that the include path of the header lib is exported to 'otherlib'
|
|
ensureContains(t, cFlags, "-Imy_include")
|
|
}
|
|
|
|
type fileInApex struct {
|
|
path string // path in apex
|
|
src string // src path
|
|
isLink bool
|
|
}
|
|
|
|
func getFiles(t *testing.T, ctx *android.TestContext, moduleName, variant string) []fileInApex {
|
|
t.Helper()
|
|
apexRule := ctx.ModuleForTests(moduleName, variant).Rule("apexRule")
|
|
copyCmds := apexRule.Args["copy_commands"]
|
|
imageApexDir := "/image.apex/"
|
|
var ret []fileInApex
|
|
for _, cmd := range strings.Split(copyCmds, "&&") {
|
|
cmd = strings.TrimSpace(cmd)
|
|
if cmd == "" {
|
|
continue
|
|
}
|
|
terms := strings.Split(cmd, " ")
|
|
var dst, src string
|
|
var isLink bool
|
|
switch terms[0] {
|
|
case "mkdir":
|
|
case "cp":
|
|
if len(terms) != 3 && len(terms) != 4 {
|
|
t.Fatal("copyCmds contains invalid cp command", cmd)
|
|
}
|
|
dst = terms[len(terms)-1]
|
|
src = terms[len(terms)-2]
|
|
isLink = false
|
|
case "ln":
|
|
if len(terms) != 3 && len(terms) != 4 {
|
|
// ln LINK TARGET or ln -s LINK TARGET
|
|
t.Fatal("copyCmds contains invalid ln command", cmd)
|
|
}
|
|
dst = terms[len(terms)-1]
|
|
src = terms[len(terms)-2]
|
|
isLink = true
|
|
default:
|
|
t.Fatalf("copyCmds should contain mkdir/cp commands only: %q", cmd)
|
|
}
|
|
if dst != "" {
|
|
index := strings.Index(dst, imageApexDir)
|
|
if index == -1 {
|
|
t.Fatal("copyCmds should copy a file to image.apex/", cmd)
|
|
}
|
|
dstFile := dst[index+len(imageApexDir):]
|
|
ret = append(ret, fileInApex{path: dstFile, src: src, isLink: isLink})
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func ensureExactContents(t *testing.T, ctx *android.TestContext, moduleName, variant string, files []string) {
|
|
t.Helper()
|
|
var failed bool
|
|
var surplus []string
|
|
filesMatched := make(map[string]bool)
|
|
for _, file := range getFiles(t, ctx, moduleName, variant) {
|
|
mactchFound := false
|
|
for _, expected := range files {
|
|
if matched, _ := path.Match(expected, file.path); matched {
|
|
filesMatched[expected] = true
|
|
mactchFound = true
|
|
break
|
|
}
|
|
}
|
|
if !mactchFound {
|
|
surplus = append(surplus, file.path)
|
|
}
|
|
}
|
|
|
|
if len(surplus) > 0 {
|
|
sort.Strings(surplus)
|
|
t.Log("surplus files", surplus)
|
|
failed = true
|
|
}
|
|
|
|
if len(files) > len(filesMatched) {
|
|
var missing []string
|
|
for _, expected := range files {
|
|
if !filesMatched[expected] {
|
|
missing = append(missing, expected)
|
|
}
|
|
}
|
|
sort.Strings(missing)
|
|
t.Log("missing files", missing)
|
|
failed = true
|
|
}
|
|
if failed {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
func TestVndkApexCurrent(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex_vndk {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
}
|
|
|
|
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",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
cc_library {
|
|
name: "libvndksp",
|
|
srcs: ["mylib.cpp"],
|
|
vendor_available: true,
|
|
vndk: {
|
|
enabled: true,
|
|
support_system_process: true,
|
|
},
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
`+vndkLibrariesTxtFiles("current"))
|
|
|
|
ensureExactContents(t, ctx, "myapex", "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",
|
|
})
|
|
}
|
|
|
|
func TestVndkApexWithPrebuilt(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex_vndk {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_prebuilt_library_shared {
|
|
name: "libvndk",
|
|
srcs: ["libvndk.so"],
|
|
vendor_available: true,
|
|
vndk: {
|
|
enabled: true,
|
|
},
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
cc_prebuilt_library_shared {
|
|
name: "libvndk.arm",
|
|
srcs: ["libvndk.arm.so"],
|
|
vendor_available: true,
|
|
vndk: {
|
|
enabled: true,
|
|
},
|
|
enabled: false,
|
|
arch: {
|
|
arm: {
|
|
enabled: true,
|
|
},
|
|
},
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
`+vndkLibrariesTxtFiles("current"),
|
|
withFiles(map[string][]byte{
|
|
"libvndk.so": nil,
|
|
"libvndk.arm.so": nil,
|
|
}))
|
|
|
|
ensureExactContents(t, ctx, "myapex", "android_common_image", []string{
|
|
"lib/libvndk.so",
|
|
"lib/libvndk.arm.so",
|
|
"lib64/libvndk.so",
|
|
"lib/libc++.so",
|
|
"lib64/libc++.so",
|
|
"etc/*",
|
|
})
|
|
}
|
|
|
|
func vndkLibrariesTxtFiles(vers ...string) (result string) {
|
|
for _, v := range vers {
|
|
if v == "current" {
|
|
for _, txt := range []string{"llndk", "vndkcore", "vndksp", "vndkprivate"} {
|
|
result += `
|
|
vndk_libraries_txt {
|
|
name: "` + txt + `.libraries.txt",
|
|
}
|
|
`
|
|
}
|
|
} else {
|
|
for _, txt := range []string{"llndk", "vndkcore", "vndksp", "vndkprivate"} {
|
|
result += `
|
|
prebuilt_etc {
|
|
name: "` + txt + `.libraries.` + v + `.txt",
|
|
src: "dummy.txt",
|
|
}
|
|
`
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func TestVndkApexVersion(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex_vndk {
|
|
name: "myapex_v27",
|
|
key: "myapex.key",
|
|
file_contexts: ":myapex-file_contexts",
|
|
vndk_version: "27",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
vndk_prebuilt_shared {
|
|
name: "libvndk27",
|
|
version: "27",
|
|
vendor_available: true,
|
|
vndk: {
|
|
enabled: true,
|
|
},
|
|
target_arch: "arm64",
|
|
arch: {
|
|
arm: {
|
|
srcs: ["libvndk27_arm.so"],
|
|
},
|
|
arm64: {
|
|
srcs: ["libvndk27_arm64.so"],
|
|
},
|
|
},
|
|
apex_available: [ "myapex_v27" ],
|
|
}
|
|
|
|
vndk_prebuilt_shared {
|
|
name: "libvndk27",
|
|
version: "27",
|
|
vendor_available: true,
|
|
vndk: {
|
|
enabled: true,
|
|
},
|
|
target_arch: "x86_64",
|
|
arch: {
|
|
x86: {
|
|
srcs: ["libvndk27_x86.so"],
|
|
},
|
|
x86_64: {
|
|
srcs: ["libvndk27_x86_64.so"],
|
|
},
|
|
},
|
|
}
|
|
`+vndkLibrariesTxtFiles("27"),
|
|
withFiles(map[string][]byte{
|
|
"libvndk27_arm.so": nil,
|
|
"libvndk27_arm64.so": nil,
|
|
"libvndk27_x86.so": nil,
|
|
"libvndk27_x86_64.so": nil,
|
|
}))
|
|
|
|
ensureExactContents(t, ctx, "myapex_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, `
|
|
apex_vndk {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
file_contexts: ":myapex-file_contexts",
|
|
}
|
|
apex_vndk {
|
|
name: "myapex_v28",
|
|
key: "myapex.key",
|
|
file_contexts: ":myapex-file_contexts",
|
|
vndk_version: "28",
|
|
}
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}`+vndkLibrariesTxtFiles("28", "current"))
|
|
|
|
assertApexName := func(expected, moduleName string) {
|
|
bundle := ctx.ModuleForTests(moduleName, "android_common_image").Module().(*apexBundle)
|
|
actual := proptools.String(bundle.properties.Apex_name)
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Errorf("Got '%v', expected '%v'", actual, expected)
|
|
}
|
|
}
|
|
|
|
assertApexName("com.android.vndk.vVER", "myapex")
|
|
assertApexName("com.android.vndk.v28", "myapex_v28")
|
|
}
|
|
|
|
func TestVndkApexSkipsNativeBridgeSupportedModules(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex_vndk {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
file_contexts: ":myapex-file_contexts",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libvndk",
|
|
srcs: ["mylib.cpp"],
|
|
vendor_available: true,
|
|
native_bridge_supported: true,
|
|
host_supported: true,
|
|
vndk: {
|
|
enabled: true,
|
|
},
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
`+vndkLibrariesTxtFiles("current"), withNativeBridgeEnabled)
|
|
|
|
ensureExactContents(t, ctx, "myapex", "android_common_image", []string{
|
|
"lib/libvndk.so",
|
|
"lib64/libvndk.so",
|
|
"lib/libc++.so",
|
|
"lib64/libc++.so",
|
|
"etc/*",
|
|
})
|
|
}
|
|
|
|
func TestVndkApexDoesntSupportNativeBridgeSupported(t *testing.T) {
|
|
testApexError(t, `module "myapex" .*: native_bridge_supported: .* doesn't support native bridge binary`, `
|
|
apex_vndk {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
file_contexts: ":myapex-file_contexts",
|
|
native_bridge_supported: true,
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libvndk",
|
|
srcs: ["mylib.cpp"],
|
|
vendor_available: true,
|
|
native_bridge_supported: true,
|
|
host_supported: true,
|
|
vndk: {
|
|
enabled: true,
|
|
},
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
}
|
|
`)
|
|
}
|
|
|
|
func TestVndkApexWithBinder32(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex_vndk {
|
|
name: "myapex_v27",
|
|
key: "myapex.key",
|
|
file_contexts: ":myapex-file_contexts",
|
|
vndk_version: "27",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
vndk_prebuilt_shared {
|
|
name: "libvndk27",
|
|
version: "27",
|
|
target_arch: "arm",
|
|
vendor_available: true,
|
|
vndk: {
|
|
enabled: true,
|
|
},
|
|
arch: {
|
|
arm: {
|
|
srcs: ["libvndk27.so"],
|
|
}
|
|
},
|
|
}
|
|
|
|
vndk_prebuilt_shared {
|
|
name: "libvndk27",
|
|
version: "27",
|
|
target_arch: "arm",
|
|
binder32bit: true,
|
|
vendor_available: true,
|
|
vndk: {
|
|
enabled: true,
|
|
},
|
|
arch: {
|
|
arm: {
|
|
srcs: ["libvndk27binder32.so"],
|
|
}
|
|
},
|
|
apex_available: [ "myapex_v27" ],
|
|
}
|
|
`+vndkLibrariesTxtFiles("27"),
|
|
withFiles(map[string][]byte{
|
|
"libvndk27.so": nil,
|
|
"libvndk27binder32.so": nil,
|
|
}),
|
|
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: ""},
|
|
},
|
|
}),
|
|
)
|
|
|
|
ensureExactContents(t, ctx, "myapex_v27", "android_common_image", []string{
|
|
"lib/libvndk27binder32.so",
|
|
"etc/*",
|
|
})
|
|
}
|
|
|
|
func TestVndkApexShouldNotProvideNativeLibs(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex_vndk {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
file_contexts: ":myapex-file_contexts",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libz",
|
|
vendor_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("myapex", "android_common_image").Rule("apexManifestRule")
|
|
provideNativeLibs := names(apexManifestRule.Args["provideNativeLibs"])
|
|
ensureListEmpty(t, provideNativeLibs)
|
|
}
|
|
|
|
func TestDependenciesInApexManifest(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex_nodep",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["lib_nodep"],
|
|
compile_multilib: "both",
|
|
file_contexts: ":myapex-file_contexts",
|
|
}
|
|
|
|
apex {
|
|
name: "myapex_dep",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["lib_dep"],
|
|
compile_multilib: "both",
|
|
file_contexts: ":myapex-file_contexts",
|
|
}
|
|
|
|
apex {
|
|
name: "myapex_provider",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["libfoo"],
|
|
compile_multilib: "both",
|
|
file_contexts: ":myapex-file_contexts",
|
|
}
|
|
|
|
apex {
|
|
name: "myapex_selfcontained",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["lib_dep", "libfoo"],
|
|
compile_multilib: "both",
|
|
file_contexts: ":myapex-file_contexts",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "lib_nodep",
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [ "myapex_nodep" ],
|
|
}
|
|
|
|
cc_library {
|
|
name: "lib_dep",
|
|
srcs: ["mylib.cpp"],
|
|
shared_libs: ["libfoo"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [
|
|
"myapex_dep",
|
|
"myapex_provider",
|
|
"myapex_selfcontained",
|
|
],
|
|
}
|
|
|
|
cc_library {
|
|
name: "libfoo",
|
|
srcs: ["mytest.cpp"],
|
|
stubs: {
|
|
versions: ["1"],
|
|
},
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [
|
|
"myapex_provider",
|
|
"myapex_selfcontained",
|
|
],
|
|
}
|
|
`)
|
|
|
|
var apexManifestRule android.TestingBuildParams
|
|
var provideNativeLibs, requireNativeLibs []string
|
|
|
|
apexManifestRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep_image").Rule("apexManifestRule")
|
|
provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
|
|
requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
|
|
ensureListEmpty(t, provideNativeLibs)
|
|
ensureListEmpty(t, requireNativeLibs)
|
|
|
|
apexManifestRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep_image").Rule("apexManifestRule")
|
|
provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
|
|
requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
|
|
ensureListEmpty(t, provideNativeLibs)
|
|
ensureListContains(t, requireNativeLibs, "libfoo.so")
|
|
|
|
apexManifestRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider_image").Rule("apexManifestRule")
|
|
provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
|
|
requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
|
|
ensureListContains(t, provideNativeLibs, "libfoo.so")
|
|
ensureListEmpty(t, requireNativeLibs)
|
|
|
|
apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained_image").Rule("apexManifestRule")
|
|
provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
|
|
requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
|
|
ensureListContains(t, provideNativeLibs, "libfoo.so")
|
|
ensureListEmpty(t, requireNativeLibs)
|
|
}
|
|
|
|
func TestApexName(t *testing.T) {
|
|
ctx, config := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
apex_name: "com.android.myapex",
|
|
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",
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"myapex",
|
|
],
|
|
}
|
|
`)
|
|
|
|
module := ctx.ModuleForTests("myapex", "android_common_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)
|
|
name := apexBundle.BaseModuleName()
|
|
prefix := "TARGET_"
|
|
var builder strings.Builder
|
|
data.Custom(&builder, name, prefix, "", data)
|
|
androidMk := builder.String()
|
|
ensureContains(t, androidMk, "LOCAL_MODULE := mylib.myapex\n")
|
|
ensureNotContains(t, androidMk, "LOCAL_MODULE := mylib.com.android.myapex\n")
|
|
}
|
|
|
|
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",
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"myapex",
|
|
],
|
|
}
|
|
`)
|
|
|
|
module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
|
|
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_shared_apex10000")
|
|
|
|
// 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 _shared
|
|
ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared")
|
|
|
|
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) {
|
|
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",
|
|
// TODO: remove //apex_available:platform
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"myapex",
|
|
],
|
|
}
|
|
`)
|
|
|
|
module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
|
|
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_shared_apex10000")
|
|
|
|
// 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 _shared
|
|
ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_shared")
|
|
}
|
|
|
|
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",
|
|
// TODO: remove //apex_available:platform
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"myapex",
|
|
],
|
|
}
|
|
|
|
cc_library {
|
|
name: "mylib_common",
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
compile_multilib: "first",
|
|
// TODO: remove //apex_available:platform
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"myapex",
|
|
],
|
|
}
|
|
|
|
cc_library {
|
|
name: "mylib2",
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
compile_multilib: "first",
|
|
}
|
|
`)
|
|
|
|
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").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_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")
|
|
ensureContains(t, copyCmds, "image.apex/lib64/mylib_common.so")
|
|
ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so")
|
|
|
|
// Ensure that the platform variant ends with _shared
|
|
ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared")
|
|
ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared")
|
|
ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_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_image").Rule("apexRule")
|
|
copyCmds := apexRule.Args["copy_commands"]
|
|
|
|
ensureContains(t, copyCmds, "image.apex/bin/script/myscript.sh")
|
|
}
|
|
|
|
func TestApexInVariousPartition(t *testing.T) {
|
|
testcases := []struct {
|
|
propName, parition, flattenedPartition string
|
|
}{
|
|
{"", "system", "system_ext"},
|
|
{"product_specific: true", "product", "product"},
|
|
{"soc_specific: true", "vendor", "vendor"},
|
|
{"proprietary: true", "vendor", "vendor"},
|
|
{"vendor: true", "vendor", "vendor"},
|
|
{"system_ext_specific: true", "system_ext", "system_ext"},
|
|
}
|
|
for _, tc := range testcases {
|
|
t.Run(tc.propName+":"+tc.parition, func(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
`+tc.propName+`
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
`)
|
|
|
|
apex := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
|
|
expected := buildDir + "/target/product/test_device/" + tc.parition + "/apex"
|
|
actual := apex.installDir.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()
|
|
if actual != expected {
|
|
t.Errorf("wrong install path. expected %q. actual %q", expected, actual)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFileContexts_FindInDefaultLocationIfNotSet(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
`)
|
|
module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
|
|
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_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_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",
|
|
}
|
|
|
|
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")
|
|
rule := module.Output("file_contexts")
|
|
ensureContains(t, rule.RuleParams.Command, "cat product_specific_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",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
filegroup {
|
|
name: "my-file-contexts",
|
|
srcs: ["product_specific_file_contexts"],
|
|
}
|
|
`, withFiles(map[string][]byte{
|
|
"product_specific_file_contexts": nil,
|
|
}))
|
|
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, `
|
|
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",
|
|
},
|
|
},
|
|
}
|
|
`)
|
|
|
|
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())
|
|
}
|
|
}
|
|
|
|
func TestPrebuiltFilenameOverride(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
prebuilt_apex {
|
|
name: "myapex",
|
|
src: "myapex-arm.apex",
|
|
filename: "notmyapex.apex",
|
|
}
|
|
`)
|
|
|
|
p := ctx.ModuleForTests("myapex", "android_common").Module().(*Prebuilt)
|
|
|
|
expected := "notmyapex.apex"
|
|
if p.installFilename != expected {
|
|
t.Errorf("installFilename invalid. expected: %q, actual: %q", expected, p.installFilename)
|
|
}
|
|
}
|
|
|
|
func TestPrebuiltOverrides(t *testing.T) {
|
|
ctx, config := testApex(t, `
|
|
prebuilt_apex {
|
|
name: "myapex.prebuilt",
|
|
src: "myapex-arm.apex",
|
|
overrides: [
|
|
"myapex",
|
|
],
|
|
}
|
|
`)
|
|
|
|
p := ctx.ModuleForTests("myapex.prebuilt", "android_common").Module().(*Prebuilt)
|
|
|
|
expected := []string{"myapex"}
|
|
actual := android.AndroidMkEntriesForTest(t, config, "", p)[0].EntryMap["LOCAL_OVERRIDES_MODULES"]
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Errorf("Incorrect LOCAL_OVERRIDES_MODULES value '%s', expected '%s'", actual, expected)
|
|
}
|
|
}
|
|
|
|
func TestApexWithTests(t *testing.T) {
|
|
ctx, config := testApex(t, `
|
|
apex_test {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
tests: [
|
|
"mytest",
|
|
"mytests",
|
|
],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
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 {
|
|
name: "mytests",
|
|
gtest: false,
|
|
srcs: [
|
|
"mytest1.cpp",
|
|
"mytest2.cpp",
|
|
"mytest3.cpp",
|
|
],
|
|
test_per_src: true,
|
|
relative_install_path: "test",
|
|
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 (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")
|
|
ensureContains(t, copyCmds, "image.apex/bin/test/mytest2")
|
|
ensureContains(t, copyCmds, "image.apex/bin/test/mytest3")
|
|
|
|
// Ensure the module is correctly translated.
|
|
bundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
|
|
data := android.AndroidMkDataForTest(t, config, "", bundle)
|
|
name := bundle.BaseModuleName()
|
|
prefix := "TARGET_"
|
|
var builder strings.Builder
|
|
data.Custom(&builder, name, prefix, "", data)
|
|
androidMk := builder.String()
|
|
ensureContains(t, androidMk, "LOCAL_MODULE := mytest.myapex\n")
|
|
ensureContains(t, androidMk, "LOCAL_MODULE := mytest1.myapex\n")
|
|
ensureContains(t, androidMk, "LOCAL_MODULE := mytest2.myapex\n")
|
|
ensureContains(t, androidMk, "LOCAL_MODULE := mytest3.myapex\n")
|
|
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, config, "", 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, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
}
|
|
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)
|
|
})
|
|
ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
|
|
ensureListContains(t, ab.requiredDeps, "myapex.flattened")
|
|
mk := android.AndroidMkDataForTest(t, config, "", 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, `
|
|
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,
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "mylib",
|
|
srcs: ["mylib.cpp"],
|
|
shared_libs: ["libcommon"],
|
|
system_shared_libs: [],
|
|
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",
|
|
],
|
|
}
|
|
`)
|
|
|
|
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_apex10000")
|
|
ensureListContains(t, ctx.ModuleVariantsForTests("libcommon"), "android_arm64_armv8-a_shared_apex10000")
|
|
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`, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
uses: ["commonapex"],
|
|
}
|
|
|
|
apex {
|
|
name: "commonapex",
|
|
key: "myapex.key",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
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",
|
|
}
|
|
`)
|
|
}
|
|
|
|
func TestApexUsesFailsIfUseVenderMismatch(t *testing.T) {
|
|
testApexError(t, `use_vendor: "commonapex" has different value of use_vendor`, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
use_vendor: true,
|
|
uses: ["commonapex"],
|
|
}
|
|
|
|
apex {
|
|
name: "commonapex",
|
|
key: "myapex.key",
|
|
provide_cpp_shared_libs: true,
|
|
}
|
|
|
|
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"})
|
|
})
|
|
}
|
|
|
|
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,
|
|
apex_available: ["myapex"],
|
|
}
|
|
`)
|
|
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"],
|
|
}
|
|
`)
|
|
}
|
|
|
|
func TestApexWithApps(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
apps: [
|
|
"AppFoo",
|
|
"AppFooPriv",
|
|
],
|
|
}
|
|
|
|
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",
|
|
system_modules: "none",
|
|
jni_libs: ["libjni"],
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
android_app {
|
|
name: "AppFooPriv",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
sdk_version: "current",
|
|
system_modules: "none",
|
|
privileged: true,
|
|
stl: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
cc_library_shared {
|
|
name: "libjni",
|
|
srcs: ["mylib.cpp"],
|
|
shared_libs: ["libfoo"],
|
|
stl: "none",
|
|
system_shared_libs: [],
|
|
apex_available: [ "myapex" ],
|
|
sdk_version: "current",
|
|
}
|
|
|
|
cc_library_shared {
|
|
name: "libfoo",
|
|
stl: "none",
|
|
system_shared_libs: [],
|
|
apex_available: [ "myapex" ],
|
|
sdk_version: "current",
|
|
}
|
|
`)
|
|
|
|
module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
|
|
apexRule := module.Rule("apexRule")
|
|
copyCmds := apexRule.Args["copy_commands"]
|
|
|
|
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_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_apex10000").Module().(*cc.Module).OutputFile()
|
|
// ... embedded inside APK (jnilibs.zip)
|
|
ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String())
|
|
// ... and not directly inside the APEX
|
|
ensureNotContains(t, copyCmds, "image.apex/lib64/"+jni+".so")
|
|
}
|
|
}
|
|
|
|
func TestApexWithAppImports(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
apps: [
|
|
"AppFooPrebuilt",
|
|
"AppFooPrivPrebuilt",
|
|
],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
android_app_import {
|
|
name: "AppFooPrebuilt",
|
|
apk: "PrebuiltAppFoo.apk",
|
|
presigned: true,
|
|
dex_preopt: {
|
|
enabled: false,
|
|
},
|
|
apex_available: ["myapex"],
|
|
}
|
|
|
|
android_app_import {
|
|
name: "AppFooPrivPrebuilt",
|
|
apk: "PrebuiltAppFooPriv.apk",
|
|
privileged: true,
|
|
presigned: true,
|
|
dex_preopt: {
|
|
enabled: false,
|
|
},
|
|
filename: "AwesomePrebuiltAppFooPriv.apk",
|
|
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/app/AppFooPrebuilt/AppFooPrebuilt.apk")
|
|
ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPrivPrebuilt/AwesomePrebuiltAppFooPriv.apk")
|
|
}
|
|
|
|
func TestApexWithAppImportsPrefer(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
apps: [
|
|
"AppFoo",
|
|
],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
android_app {
|
|
name: "AppFoo",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
android_app_import {
|
|
name: "AppFoo",
|
|
apk: "AppFooPrebuilt.apk",
|
|
filename: "AppFooPrebuilt.apk",
|
|
presigned: true,
|
|
prefer: true,
|
|
apex_available: ["myapex"],
|
|
}
|
|
`, withFiles(map[string][]byte{
|
|
"AppFooPrebuilt.apk": nil,
|
|
}))
|
|
|
|
ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
|
|
"app/AppFoo/AppFooPrebuilt.apk",
|
|
})
|
|
}
|
|
|
|
func TestApexWithTestHelperApp(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
apps: [
|
|
"TesterHelpAppFoo",
|
|
],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
android_test_helper_app {
|
|
name: "TesterHelpAppFoo",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
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/app/TesterHelpAppFoo/TesterHelpAppFoo.apk")
|
|
}
|
|
|
|
func TestApexPropertiesShouldBeDefaultable(t *testing.T) {
|
|
// libfoo's apex_available comes from cc_defaults
|
|
testApexError(t, `requires "libfoo" that is not available for the APEX`, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["libfoo"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
apex {
|
|
name: "otherapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["libfoo"],
|
|
}
|
|
|
|
cc_defaults {
|
|
name: "libfoo-defaults",
|
|
apex_available: ["otherapex"],
|
|
}
|
|
|
|
cc_library {
|
|
name: "libfoo",
|
|
defaults: ["libfoo-defaults"],
|
|
stl: "none",
|
|
system_shared_libs: [],
|
|
}`)
|
|
}
|
|
|
|
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", `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["libfoo"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
apex {
|
|
name: "otherapex",
|
|
key: "otherapex.key",
|
|
native_shared_libs: ["libfoo"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "otherapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libfoo",
|
|
stl: "none",
|
|
system_shared_libs: [],
|
|
apex_available: ["otherapex"],
|
|
}`)
|
|
}
|
|
|
|
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.*name:sharedLib.*
|
|
.*-> libfoo.*link:shared.*
|
|
.*via tag cc\.libraryDependencyTag.*Kind:sharedLibraryDependency.*
|
|
.*-> libbar.*link:shared.*
|
|
.*via tag cc\.libraryDependencyTag.*Kind:sharedLibraryDependency.*
|
|
.*-> libbaz.*link:shared.*`, `
|
|
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",
|
|
shared_libs: ["libbar"],
|
|
system_shared_libs: [],
|
|
apex_available: ["myapex"],
|
|
}
|
|
|
|
cc_library {
|
|
name: "libbar",
|
|
stl: "none",
|
|
shared_libs: ["libbaz"],
|
|
system_shared_libs: [],
|
|
apex_available: ["myapex"],
|
|
}
|
|
|
|
cc_library {
|
|
name: "libbaz",
|
|
stl: "none",
|
|
system_shared_libs: [],
|
|
}`)
|
|
}
|
|
|
|
func TestApexAvailable_InvalidApexName(t *testing.T) {
|
|
testApexError(t, "\"otherapex\" is not a valid module name", `
|
|
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: [],
|
|
apex_available: ["otherapex"],
|
|
}`)
|
|
|
|
testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["libfoo", "libbar"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libfoo",
|
|
stl: "none",
|
|
system_shared_libs: [],
|
|
runtime_libs: ["libbaz"],
|
|
apex_available: ["myapex"],
|
|
}
|
|
|
|
cc_library {
|
|
name: "libbar",
|
|
stl: "none",
|
|
system_shared_libs: [],
|
|
apex_available: ["//apex_available:anyapex"],
|
|
}
|
|
|
|
cc_library {
|
|
name: "libbaz",
|
|
stl: "none",
|
|
system_shared_libs: [],
|
|
stubs: {
|
|
versions: ["10", "20", "30"],
|
|
},
|
|
}`)
|
|
}
|
|
|
|
func TestApexAvailable_CheckForPlatform(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["libbar", "libbaz"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "libfoo",
|
|
stl: "none",
|
|
system_shared_libs: [],
|
|
shared_libs: ["libbar"],
|
|
apex_available: ["//apex_available:platform"],
|
|
}
|
|
|
|
cc_library {
|
|
name: "libfoo2",
|
|
stl: "none",
|
|
system_shared_libs: [],
|
|
shared_libs: ["libbaz"],
|
|
apex_available: ["//apex_available:platform"],
|
|
}
|
|
|
|
cc_library {
|
|
name: "libbar",
|
|
stl: "none",
|
|
system_shared_libs: [],
|
|
apex_available: ["myapex"],
|
|
}
|
|
|
|
cc_library {
|
|
name: "libbaz",
|
|
stl: "none",
|
|
system_shared_libs: [],
|
|
apex_available: ["myapex"],
|
|
stubs: {
|
|
versions: ["1"],
|
|
},
|
|
}`)
|
|
|
|
// libfoo shouldn't be available to platform even though it has "//apex_available:platform",
|
|
// because it depends on libbar which isn't available to platform
|
|
libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*cc.Module)
|
|
if libfoo.NotAvailableForPlatform() != true {
|
|
t.Errorf("%q shouldn't be available to platform", libfoo.String())
|
|
}
|
|
|
|
// libfoo2 however can be available to platform because it depends on libbaz which provides
|
|
// stubs
|
|
libfoo2 := ctx.ModuleForTests("libfoo2", "android_arm64_armv8-a_shared").Module().(*cc.Module)
|
|
if libfoo2.NotAvailableForPlatform() == true {
|
|
t.Errorf("%q should be available to platform", libfoo2.String())
|
|
}
|
|
}
|
|
|
|
func TestApexAvailable_CreatedForApex(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
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: [],
|
|
apex_available: ["myapex"],
|
|
static: {
|
|
apex_available: ["//apex_available:platform"],
|
|
},
|
|
}`)
|
|
|
|
libfooShared := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*cc.Module)
|
|
if libfooShared.NotAvailableForPlatform() != true {
|
|
t.Errorf("%q shouldn't be available to platform", libfooShared.String())
|
|
}
|
|
libfooStatic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Module().(*cc.Module)
|
|
if libfooStatic.NotAvailableForPlatform() != false {
|
|
t.Errorf("%q should be available to platform", libfooStatic.String())
|
|
}
|
|
}
|
|
|
|
func TestOverrideApex(t *testing.T) {
|
|
ctx, config := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
apps: ["app"],
|
|
overrides: ["oldapex"],
|
|
}
|
|
|
|
override_apex {
|
|
name: "override_myapex",
|
|
base: "myapex",
|
|
apps: ["override_app"],
|
|
overrides: ["unknownapex"],
|
|
logging_parent: "com.foo.bar",
|
|
package_name: "test.overridden.package",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
android_app {
|
|
name: "app",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
package_name: "foo",
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
|
|
override_android_app {
|
|
name: "override_app",
|
|
base: "app",
|
|
package_name: "bar",
|
|
}
|
|
`, withManifestPackageNameOverrides([]string{"myapex:com.android.myapex"}))
|
|
|
|
originalVariant := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(android.OverridableModule)
|
|
overriddenVariant := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image").Module().(android.OverridableModule)
|
|
if originalVariant.GetOverriddenBy() != "" {
|
|
t.Errorf("GetOverriddenBy should be empty, but was %q", originalVariant.GetOverriddenBy())
|
|
}
|
|
if overriddenVariant.GetOverriddenBy() != "override_myapex" {
|
|
t.Errorf("GetOverriddenBy should be \"override_myapex\", but was %q", overriddenVariant.GetOverriddenBy())
|
|
}
|
|
|
|
module := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image")
|
|
apexRule := module.Rule("apexRule")
|
|
copyCmds := apexRule.Args["copy_commands"]
|
|
|
|
ensureNotContains(t, copyCmds, "image.apex/app/app/app.apk")
|
|
ensureContains(t, copyCmds, "image.apex/app/override_app/override_app.apk")
|
|
|
|
apexBundle := module.Module().(*apexBundle)
|
|
name := apexBundle.Name()
|
|
if name != "override_myapex" {
|
|
t.Errorf("name should be \"override_myapex\", but was %q", name)
|
|
}
|
|
|
|
if apexBundle.overridableProperties.Logging_parent != "com.foo.bar" {
|
|
t.Errorf("override_myapex should have logging parent (com.foo.bar), but was %q.", apexBundle.overridableProperties.Logging_parent)
|
|
}
|
|
|
|
optFlags := apexRule.Args["opt_flags"]
|
|
ensureContains(t, optFlags, "--override_apk_package_name test.overridden.package")
|
|
|
|
data := android.AndroidMkDataForTest(t, config, "", apexBundle)
|
|
var builder strings.Builder
|
|
data.Custom(&builder, name, "TARGET_", "", data)
|
|
androidMk := builder.String()
|
|
ensureContains(t, androidMk, "LOCAL_MODULE := override_app.override_myapex")
|
|
ensureContains(t, androidMk, "LOCAL_MODULE := apex_manifest.pb.override_myapex")
|
|
ensureContains(t, androidMk, "LOCAL_MODULE_STEM := override_myapex.apex")
|
|
ensureContains(t, androidMk, "LOCAL_OVERRIDES_MODULES := unknownapex myapex")
|
|
ensureNotContains(t, androidMk, "LOCAL_MODULE := app.myapex")
|
|
ensureNotContains(t, androidMk, "LOCAL_MODULE := override_app.myapex")
|
|
ensureNotContains(t, androidMk, "LOCAL_MODULE := apex_manifest.pb.myapex")
|
|
ensureNotContains(t, androidMk, "LOCAL_MODULE_STEM := myapex.apex")
|
|
}
|
|
|
|
func TestLegacyAndroid10Support(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",
|
|
}
|
|
|
|
cc_library {
|
|
name: "mylib",
|
|
srcs: ["mylib.cpp"],
|
|
stl: "libc++",
|
|
system_shared_libs: [],
|
|
apex_available: [ "myapex" ],
|
|
min_sdk_version: "29",
|
|
}
|
|
`, withUnbundledBuild)
|
|
|
|
module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
|
|
args := module.Rule("apexRule").Args
|
|
ensureContains(t, args["opt_flags"], "--manifest_json "+module.Output("apex_manifest.json").Output.String())
|
|
ensureNotContains(t, args["opt_flags"], "--no_hashtree")
|
|
|
|
// The copies of the libraries in the apex should have one more dependency than
|
|
// the ones outside the apex, namely the unwinder. Ideally we should check
|
|
// 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_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)
|
|
}
|
|
}
|
|
}
|
|
|
|
var filesForSdkLibrary = map[string][]byte{
|
|
"api/current.txt": nil,
|
|
"api/removed.txt": nil,
|
|
"api/system-current.txt": nil,
|
|
"api/system-removed.txt": nil,
|
|
"api/test-current.txt": nil,
|
|
"api/test-removed.txt": nil,
|
|
|
|
// For java_sdk_library_import
|
|
"a.jar": nil,
|
|
}
|
|
|
|
func TestJavaSDKLibrary(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
java_libs: ["foo"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
java_sdk_library {
|
|
name: "foo",
|
|
srcs: ["a.java"],
|
|
api_packages: ["foo"],
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
`, withFiles(filesForSdkLibrary))
|
|
|
|
// java_sdk_library installs both impl jar and permission XML
|
|
ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
|
|
"javalib/foo.jar",
|
|
"etc/permissions/foo.xml",
|
|
})
|
|
// Permission XML should point to the activated path of impl jar of java_sdk_library
|
|
sdkLibrary := ctx.ModuleForTests("foo.xml", "android_common_myapex").Rule("java_sdk_xml")
|
|
ensureContains(t, sdkLibrary.RuleParams.Command, `<library name=\"foo\" file=\"/apex/myapex/javalib/foo.jar\"`)
|
|
}
|
|
|
|
func TestJavaSDKLibrary_WithinApex(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
java_libs: ["foo", "bar"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
java_sdk_library {
|
|
name: "foo",
|
|
srcs: ["a.java"],
|
|
api_packages: ["foo"],
|
|
apex_available: ["myapex"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
}
|
|
|
|
java_library {
|
|
name: "bar",
|
|
srcs: ["a.java"],
|
|
libs: ["foo"],
|
|
apex_available: ["myapex"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
}
|
|
`, withFiles(filesForSdkLibrary))
|
|
|
|
// java_sdk_library installs both impl jar and permission XML
|
|
ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
|
|
"javalib/bar.jar",
|
|
"javalib/foo.jar",
|
|
"etc/permissions/foo.xml",
|
|
})
|
|
|
|
// 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) {
|
|
t.Errorf("expected %q, found %#q", expected, actual)
|
|
}
|
|
}
|
|
|
|
func TestJavaSDKLibrary_CrossBoundary(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
java_libs: ["foo"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
java_sdk_library {
|
|
name: "foo",
|
|
srcs: ["a.java"],
|
|
api_packages: ["foo"],
|
|
apex_available: ["myapex"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
}
|
|
|
|
java_library {
|
|
name: "bar",
|
|
srcs: ["a.java"],
|
|
libs: ["foo"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
}
|
|
`, withFiles(filesForSdkLibrary))
|
|
|
|
// java_sdk_library installs both impl jar and permission XML
|
|
ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
|
|
"javalib/foo.jar",
|
|
"etc/permissions/foo.xml",
|
|
})
|
|
|
|
// 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) {
|
|
t.Errorf("expected %q, found %#q", expected, actual)
|
|
}
|
|
}
|
|
|
|
func TestJavaSDKLibrary_ImportPreferred(t *testing.T) {
|
|
ctx, _ := testApex(t, ``,
|
|
withFiles(map[string][]byte{
|
|
"apex/a.java": nil,
|
|
"apex/apex_manifest.json": nil,
|
|
"apex/Android.bp": []byte(`
|
|
package {
|
|
default_visibility: ["//visibility:private"],
|
|
}
|
|
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
java_libs: ["foo", "bar"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
java_library {
|
|
name: "bar",
|
|
srcs: ["a.java"],
|
|
libs: ["foo"],
|
|
apex_available: ["myapex"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
}
|
|
`),
|
|
"source/a.java": nil,
|
|
"source/api/current.txt": nil,
|
|
"source/api/removed.txt": nil,
|
|
"source/Android.bp": []byte(`
|
|
package {
|
|
default_visibility: ["//visibility:private"],
|
|
}
|
|
|
|
java_sdk_library {
|
|
name: "foo",
|
|
visibility: ["//apex"],
|
|
srcs: ["a.java"],
|
|
api_packages: ["foo"],
|
|
apex_available: ["myapex"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
public: {
|
|
enabled: true,
|
|
},
|
|
}
|
|
`),
|
|
"prebuilt/a.jar": nil,
|
|
"prebuilt/Android.bp": []byte(`
|
|
package {
|
|
default_visibility: ["//visibility:private"],
|
|
}
|
|
|
|
java_sdk_library_import {
|
|
name: "foo",
|
|
visibility: ["//apex", "//source"],
|
|
apex_available: ["myapex"],
|
|
prefer: true,
|
|
public: {
|
|
jars: ["a.jar"],
|
|
},
|
|
}
|
|
`),
|
|
}),
|
|
)
|
|
|
|
// java_sdk_library installs both impl jar and permission XML
|
|
ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
|
|
"javalib/bar.jar",
|
|
"javalib/foo.jar",
|
|
"etc/permissions/foo.xml",
|
|
})
|
|
|
|
// 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) {
|
|
t.Errorf("expected %q, found %#q", expected, actual)
|
|
}
|
|
}
|
|
|
|
func TestJavaSDKLibrary_ImportOnly(t *testing.T) {
|
|
testApexError(t, `java_libs: "foo" is not configured to be compiled into dex`, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
java_libs: ["foo"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
java_sdk_library_import {
|
|
name: "foo",
|
|
apex_available: ["myapex"],
|
|
prefer: true,
|
|
public: {
|
|
jars: ["a.jar"],
|
|
},
|
|
}
|
|
|
|
`, withFiles(filesForSdkLibrary))
|
|
}
|
|
|
|
func TestCompatConfig(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
prebuilts: ["myjar-platform-compat-config"],
|
|
java_libs: ["myjar"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
platform_compat_config {
|
|
name: "myjar-platform-compat-config",
|
|
src: ":myjar",
|
|
}
|
|
|
|
java_library {
|
|
name: "myjar",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
`)
|
|
ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
|
|
"etc/compatconfig/myjar-platform-compat-config.xml",
|
|
"javalib/myjar.jar",
|
|
})
|
|
}
|
|
|
|
func TestRejectNonInstallableJavaLibrary(t *testing.T) {
|
|
testApexError(t, `"myjar" is not configured to be compiled into dex`, `
|
|
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",
|
|
compile_dex: false,
|
|
apex_available: ["myapex"],
|
|
}
|
|
`)
|
|
}
|
|
|
|
func TestCarryRequiredModuleNames(t *testing.T) {
|
|
ctx, config := 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",
|
|
required: ["a", "b"],
|
|
host_required: ["c", "d"],
|
|
target_required: ["e", "f"],
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
`)
|
|
|
|
apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
|
|
data := android.AndroidMkDataForTest(t, config, "", 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 += a b\n")
|
|
ensureContains(t, androidMk, "LOCAL_HOST_REQUIRED_MODULES += c d\n")
|
|
ensureContains(t, androidMk, "LOCAL_TARGET_REQUIRED_MODULES += e f\n")
|
|
}
|
|
|
|
func TestSymlinksFromApexToSystem(t *testing.T) {
|
|
bp := `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["mylib"],
|
|
java_libs: ["myjar"],
|
|
}
|
|
|
|
apex {
|
|
name: "myapex.updatable",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["mylib"],
|
|
java_libs: ["myjar"],
|
|
updatable: true,
|
|
min_sdk_version: "current",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
cc_library {
|
|
name: "mylib",
|
|
srcs: ["mylib.cpp"],
|
|
shared_libs: ["myotherlib"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [
|
|
"myapex",
|
|
"myapex.updatable",
|
|
"//apex_available:platform",
|
|
],
|
|
min_sdk_version: "current",
|
|
}
|
|
|
|
cc_library {
|
|
name: "myotherlib",
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
apex_available: [
|
|
"myapex",
|
|
"myapex.updatable",
|
|
"//apex_available:platform",
|
|
],
|
|
min_sdk_version: "current",
|
|
}
|
|
|
|
java_library {
|
|
name: "myjar",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
libs: ["myotherjar"],
|
|
apex_available: [
|
|
"myapex",
|
|
"myapex.updatable",
|
|
"//apex_available:platform",
|
|
],
|
|
min_sdk_version: "current",
|
|
}
|
|
|
|
java_library {
|
|
name: "myotherjar",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
apex_available: [
|
|
"myapex",
|
|
"myapex.updatable",
|
|
"//apex_available:platform",
|
|
],
|
|
min_sdk_version: "current",
|
|
}
|
|
`
|
|
|
|
ensureRealfileExists := func(t *testing.T, files []fileInApex, file string) {
|
|
for _, f := range files {
|
|
if f.path == file {
|
|
if f.isLink {
|
|
t.Errorf("%q is not a real file", file)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
t.Errorf("%q is not found", file)
|
|
}
|
|
|
|
ensureSymlinkExists := func(t *testing.T, files []fileInApex, file string) {
|
|
for _, f := range files {
|
|
if f.path == file {
|
|
if !f.isLink {
|
|
t.Errorf("%q is not a symlink", file)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
t.Errorf("%q is not found", file)
|
|
}
|
|
|
|
// For unbundled build, symlink shouldn't exist regardless of whether an APEX
|
|
// is updatable or not
|
|
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")
|
|
ensureRealfileExists(t, files, "lib64/myotherlib.so")
|
|
|
|
files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable_image")
|
|
ensureRealfileExists(t, files, "javalib/myjar.jar")
|
|
ensureRealfileExists(t, files, "lib64/mylib.so")
|
|
ensureRealfileExists(t, files, "lib64/myotherlib.so")
|
|
|
|
// For bundled build, symlink to the system for the non-updatable APEXes only
|
|
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")
|
|
ensureSymlinkExists(t, files, "lib64/myotherlib.so") // this is symlink
|
|
|
|
files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable_image")
|
|
ensureRealfileExists(t, files, "javalib/myjar.jar")
|
|
ensureRealfileExists(t, files, "lib64/mylib.so")
|
|
ensureRealfileExists(t, files, "lib64/myotherlib.so") // this is a real file
|
|
}
|
|
|
|
func TestSymlinksFromApexToSystemRequiredModuleNames(t *testing.T) {
|
|
ctx, config := 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_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, config, "", 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 myotherlib 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"],
|
|
}
|
|
|
|
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",
|
|
}
|
|
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{}
|
|
})
|
|
|
|
if expected, got := []string{""}, ctx.ModuleVariantsForTests("myapex"); !reflect.DeepEqual(expected, got) {
|
|
t.Errorf("Expected variants: %v, but got: %v", expected, got)
|
|
}
|
|
}
|
|
|
|
func TestAppBundle(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
apps: ["AppFoo"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
android_app {
|
|
name: "AppFoo",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
`, withManifestPackageNameOverrides([]string{"AppFoo:com.android.foo"}))
|
|
|
|
bundleConfigRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Description("Bundle Config")
|
|
content := bundleConfigRule.Args["content"]
|
|
|
|
ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`)
|
|
ensureContains(t, content, `"apex_config":{"apex_embedded_apk_config":[{"package_name":"com.android.foo","path":"app/AppFoo/AppFoo.apk"}]}`)
|
|
}
|
|
|
|
func TestAppSetBundle(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
apps: ["AppSet"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
android_app_set {
|
|
name: "AppSet",
|
|
set: "AppSet.apks",
|
|
}`)
|
|
mod := ctx.ModuleForTests("myapex", "android_common_myapex_image")
|
|
bundleConfigRule := mod.Description("Bundle Config")
|
|
content := bundleConfigRule.Args["content"]
|
|
ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`)
|
|
s := mod.Rule("apexRule").Args["copy_commands"]
|
|
copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
|
|
if len(copyCmds) != 3 {
|
|
t.Fatalf("Expected 3 commands, got %d in:\n%s", len(copyCmds), s)
|
|
}
|
|
ensureMatches(t, copyCmds[0], "^rm -rf .*/app/AppSet$")
|
|
ensureMatches(t, copyCmds[1], "^mkdir -p .*/app/AppSet$")
|
|
ensureMatches(t, copyCmds[2], "^unzip .*-d .*/app/AppSet .*/AppSet.zip$")
|
|
}
|
|
|
|
func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
|
|
t.Helper()
|
|
|
|
bp := `
|
|
java_library {
|
|
name: "some-updatable-apex-lib",
|
|
srcs: ["a.java"],
|
|
sdk_version: "current",
|
|
apex_available: [
|
|
"some-updatable-apex",
|
|
],
|
|
}
|
|
|
|
java_library {
|
|
name: "some-non-updatable-apex-lib",
|
|
srcs: ["a.java"],
|
|
apex_available: [
|
|
"some-non-updatable-apex",
|
|
],
|
|
}
|
|
|
|
java_library {
|
|
name: "some-platform-lib",
|
|
srcs: ["a.java"],
|
|
sdk_version: "current",
|
|
installable: true,
|
|
}
|
|
|
|
java_library {
|
|
name: "some-art-lib",
|
|
srcs: ["a.java"],
|
|
sdk_version: "current",
|
|
apex_available: [
|
|
"com.android.art.something",
|
|
],
|
|
hostdex: true,
|
|
}
|
|
|
|
apex {
|
|
name: "some-updatable-apex",
|
|
key: "some-updatable-apex.key",
|
|
java_libs: ["some-updatable-apex-lib"],
|
|
updatable: true,
|
|
min_sdk_version: "current",
|
|
}
|
|
|
|
apex {
|
|
name: "some-non-updatable-apex",
|
|
key: "some-non-updatable-apex.key",
|
|
java_libs: ["some-non-updatable-apex-lib"],
|
|
}
|
|
|
|
apex_key {
|
|
name: "some-updatable-apex.key",
|
|
}
|
|
|
|
apex_key {
|
|
name: "some-non-updatable-apex.key",
|
|
}
|
|
|
|
apex {
|
|
name: "com.android.art.something",
|
|
key: "com.android.art.something.key",
|
|
java_libs: ["some-art-lib"],
|
|
updatable: true,
|
|
min_sdk_version: "current",
|
|
}
|
|
|
|
apex_key {
|
|
name: "com.android.art.something.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",
|
|
],
|
|
}
|
|
`
|
|
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)
|
|
android.RegisterPrebuiltMutators(ctx)
|
|
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)
|
|
}
|
|
}
|
|
|
|
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 TestNoUpdatableJarsInBootImage(t *testing.T) {
|
|
var err string
|
|
var transform func(*dexpreopt.GlobalConfig)
|
|
|
|
config := android.TestArchConfig(buildDir, nil, "", nil)
|
|
ctx := android.PathContextForTesting(config)
|
|
|
|
t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) {
|
|
transform = func(config *dexpreopt.GlobalConfig) {
|
|
config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"com.android.art.something:some-art-lib"})
|
|
}
|
|
testNoUpdatableJarsInBootImage(t, "", transform)
|
|
})
|
|
|
|
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.something"\] is not allowed in the framework boot image`
|
|
transform = func(config *dexpreopt.GlobalConfig) {
|
|
config.BootJars = android.CreateConfiguredJarList(ctx, []string{"com.android.art.something:some-art-lib"})
|
|
}
|
|
testNoUpdatableJarsInBootImage(t, err, transform)
|
|
})
|
|
|
|
t.Run("updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
|
|
err = `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the ART boot image`
|
|
transform = func(config *dexpreopt.GlobalConfig) {
|
|
config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"some-updatable-apex:some-updatable-apex-lib"})
|
|
}
|
|
testNoUpdatableJarsInBootImage(t, err, transform)
|
|
})
|
|
|
|
t.Run("non-updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
|
|
err = `module "some-non-updatable-apex-lib" is not allowed in the ART boot image`
|
|
transform = func(config *dexpreopt.GlobalConfig) {
|
|
config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"some-non-updatable-apex:some-non-updatable-apex-lib"})
|
|
}
|
|
testNoUpdatableJarsInBootImage(t, err, transform)
|
|
})
|
|
|
|
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`
|
|
transform = func(config *dexpreopt.GlobalConfig) {
|
|
config.BootJars = android.CreateConfiguredJarList(ctx, []string{"some-updatable-apex:some-updatable-apex-lib"})
|
|
}
|
|
testNoUpdatableJarsInBootImage(t, err, transform)
|
|
})
|
|
|
|
t.Run("non-updatable jar from some other apex in the framework boot image => ok", func(t *testing.T) {
|
|
transform = func(config *dexpreopt.GlobalConfig) {
|
|
config.BootJars = android.CreateConfiguredJarList(ctx, []string{"some-non-updatable-apex:some-non-updatable-apex-lib"})
|
|
}
|
|
testNoUpdatableJarsInBootImage(t, "", transform)
|
|
})
|
|
|
|
t.Run("nonexistent jar in the ART boot image => error", func(t *testing.T) {
|
|
err = "failed to find a dex jar path for module 'nonexistent'"
|
|
transform = func(config *dexpreopt.GlobalConfig) {
|
|
config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"platform:nonexistent"})
|
|
}
|
|
testNoUpdatableJarsInBootImage(t, err, transform)
|
|
})
|
|
|
|
t.Run("nonexistent jar in the framework boot image => error", func(t *testing.T) {
|
|
err = "failed to find a dex jar path for module 'nonexistent'"
|
|
transform = func(config *dexpreopt.GlobalConfig) {
|
|
config.BootJars = android.CreateConfiguredJarList(ctx, []string{"platform:nonexistent"})
|
|
}
|
|
testNoUpdatableJarsInBootImage(t, err, transform)
|
|
})
|
|
|
|
t.Run("platform jar in the ART boot image => error", func(t *testing.T) {
|
|
err = `module "some-platform-lib" is not allowed in the ART boot image`
|
|
transform = func(config *dexpreopt.GlobalConfig) {
|
|
config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"platform:some-platform-lib"})
|
|
}
|
|
testNoUpdatableJarsInBootImage(t, err, transform)
|
|
})
|
|
|
|
t.Run("platform jar in the framework boot image => ok", func(t *testing.T) {
|
|
transform = func(config *dexpreopt.GlobalConfig) {
|
|
config.BootJars = android.CreateConfiguredJarList(ctx, []string{"platform:some-platform-lib"})
|
|
}
|
|
testNoUpdatableJarsInBootImage(t, "", transform)
|
|
})
|
|
}
|
|
|
|
func testApexPermittedPackagesRules(t *testing.T, errmsg, bp string, apexBootJars []string, rules []android.Rule) {
|
|
t.Helper()
|
|
bp += `
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}`
|
|
fs := map[string][]byte{
|
|
"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)
|
|
}
|
|
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)
|
|
}
|
|
}
|
|
|
|
func TestApexPermittedPackagesRules(t *testing.T) {
|
|
testcases := []struct {
|
|
name string
|
|
expectedError string
|
|
bp string
|
|
bootJars []string
|
|
modulesPackages map[string][]string
|
|
}{
|
|
|
|
{
|
|
name: "Non-Bootclasspath apex jar not satisfying allowed module packages.",
|
|
expectedError: "",
|
|
bp: `
|
|
java_library {
|
|
name: "bcp_lib1",
|
|
srcs: ["lib1/src/*.java"],
|
|
permitted_packages: ["foo.bar"],
|
|
apex_available: ["myapex"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
}
|
|
java_library {
|
|
name: "nonbcp_lib2",
|
|
srcs: ["lib2/src/*.java"],
|
|
apex_available: ["myapex"],
|
|
permitted_packages: ["a.b"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
}
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
java_libs: ["bcp_lib1", "nonbcp_lib2"],
|
|
}`,
|
|
bootJars: []string{"bcp_lib1"},
|
|
modulesPackages: map[string][]string{
|
|
"myapex": []string{
|
|
"foo.bar",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Bootclasspath apex jar not satisfying allowed module packages.",
|
|
expectedError: `module "bcp_lib2" .* which is restricted because jars that are part of the myapex module may only allow these packages: foo.bar. Please jarjar or move code around.`,
|
|
bp: `
|
|
java_library {
|
|
name: "bcp_lib1",
|
|
srcs: ["lib1/src/*.java"],
|
|
apex_available: ["myapex"],
|
|
permitted_packages: ["foo.bar"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
}
|
|
java_library {
|
|
name: "bcp_lib2",
|
|
srcs: ["lib2/src/*.java"],
|
|
apex_available: ["myapex"],
|
|
permitted_packages: ["foo.bar", "bar.baz"],
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
}
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
java_libs: ["bcp_lib1", "bcp_lib2"],
|
|
}
|
|
`,
|
|
bootJars: []string{"bcp_lib1", "bcp_lib2"},
|
|
modulesPackages: map[string][]string{
|
|
"myapex": []string{
|
|
"foo.bar",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tc := range testcases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
rules := createApexPermittedPackagesRules(tc.modulesPackages)
|
|
testApexPermittedPackagesRules(t, tc.expectedError, tc.bp, tc.bootJars, rules)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTestFor(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
native_shared_libs: ["mylib", "myprivlib"],
|
|
}
|
|
|
|
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",
|
|
apex_available: ["myapex"],
|
|
}
|
|
|
|
|
|
cc_test {
|
|
name: "mytest",
|
|
gtest: false,
|
|
srcs: ["mylib.cpp"],
|
|
system_shared_libs: [],
|
|
stl: "none",
|
|
shared_libs: ["mylib", "myprivlib"],
|
|
test_for: ["myapex"]
|
|
}
|
|
`)
|
|
|
|
// the test 'mytest' is a test for the apex, therefore is 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")
|
|
}
|
|
|
|
// TODO(jungjw): Move this to proptools
|
|
func intPtr(i int) *int {
|
|
return &i
|
|
}
|
|
|
|
func TestApexSet(t *testing.T) {
|
|
ctx, config := 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"}}},
|
|
}
|
|
})
|
|
|
|
m := ctx.ModuleForTests("myapex", "android_common")
|
|
|
|
// Check extract_apks tool parameters.
|
|
extractedApex := m.Output(buildDir + "/.intermediates/myapex/android_common/foo_v2.apex")
|
|
actual := extractedApex.Args["abis"]
|
|
expected := "ARMEABI_V7A,ARM64_V8A"
|
|
if actual != expected {
|
|
t.Errorf("Unexpected abis parameter - expected %q vs actual %q", expected, actual)
|
|
}
|
|
actual = extractedApex.Args["sdk-version"]
|
|
expected = "30"
|
|
if actual != expected {
|
|
t.Errorf("Unexpected abis parameter - expected %q vs actual %q", expected, actual)
|
|
}
|
|
|
|
a := m.Module().(*ApexSet)
|
|
expectedOverrides := []string{"foo"}
|
|
actualOverrides := android.AndroidMkEntriesForTest(t, config, "", 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"],
|
|
}
|
|
|
|
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, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
prebuilt_apex {
|
|
name: "myapex",
|
|
prefer: true,
|
|
arch: {
|
|
arm64: {
|
|
src: "myapex-arm64.apex",
|
|
},
|
|
arm: {
|
|
src: "myapex-arm.apex",
|
|
},
|
|
},
|
|
}
|
|
|
|
apex_set {
|
|
name: "myapex_set",
|
|
set: "myapex.apks",
|
|
filename: "myapex_set.apex",
|
|
overrides: ["myapex"],
|
|
}
|
|
`)
|
|
|
|
apexKeysText := ctx.SingletonForTests("apex_keys_text")
|
|
content := apexKeysText.MaybeDescription("apexkeys.txt").BuildParams.Args["content"]
|
|
ensureContains(t, content, `name="myapex_set.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" partition="system"`)
|
|
ensureContains(t, content, `name="myapex.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" partition="system"`)
|
|
}
|
|
|
|
func TestAllowedFiles(t *testing.T) {
|
|
ctx, _ := testApex(t, `
|
|
apex {
|
|
name: "myapex",
|
|
key: "myapex.key",
|
|
apps: ["app"],
|
|
allowed_files: "allowed.txt",
|
|
}
|
|
|
|
apex_key {
|
|
name: "myapex.key",
|
|
public_key: "testkey.avbpubkey",
|
|
private_key: "testkey.pem",
|
|
}
|
|
|
|
android_app {
|
|
name: "app",
|
|
srcs: ["foo/bar/MyClass.java"],
|
|
package_name: "foo",
|
|
sdk_version: "none",
|
|
system_modules: "none",
|
|
apex_available: [ "myapex" ],
|
|
}
|
|
`, withFiles(map[string][]byte{
|
|
"sub/Android.bp": []byte(`
|
|
override_apex {
|
|
name: "override_myapex",
|
|
base: "myapex",
|
|
apps: ["override_app"],
|
|
allowed_files: ":allowed",
|
|
}
|
|
// Overridable "path" property should be referenced indirectly
|
|
filegroup {
|
|
name: "allowed",
|
|
srcs: ["allowed.txt"],
|
|
}
|
|
override_android_app {
|
|
name: "override_app",
|
|
base: "app",
|
|
package_name: "bar",
|
|
}
|
|
`),
|
|
}))
|
|
|
|
rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("diffApexContentRule")
|
|
if expected, actual := "allowed.txt", rule.Args["allowed_files_file"]; expected != actual {
|
|
t.Errorf("allowed_files_file: expected %q but got %q", expected, actual)
|
|
}
|
|
|
|
rule2 := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image").Rule("diffApexContentRule")
|
|
if expected, actual := "sub/allowed.txt", rule2.Args["allowed_files_file"]; expected != actual {
|
|
t.Errorf("allowed_files_file: expected %q but got %q", expected, actual)
|
|
}
|
|
}
|
|
|
|
func TestNonPreferredPrebuiltDependency(t *testing.T) {
|
|
_, _ = 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"],
|
|
stubs: {
|
|
versions: ["current"],
|
|
},
|
|
apex_available: ["myapex"],
|
|
}
|
|
|
|
cc_prebuilt_library_shared {
|
|
name: "mylib",
|
|
prefer: false,
|
|
srcs: ["prebuilt.so"],
|
|
stubs: {
|
|
versions: ["current"],
|
|
},
|
|
apex_available: ["myapex"],
|
|
}
|
|
`)
|
|
}
|
|
|
|
func TestMain(m *testing.M) {
|
|
run := func() int {
|
|
setUp()
|
|
defer tearDown()
|
|
|
|
return m.Run()
|
|
}
|
|
|
|
os.Exit(run())
|
|
}
|