Loading Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -353,6 +353,9 @@ bootstrap_go_package { "apex/apex.go", "apex/key.go", ], testSrcs: [ "apex/apex_test.go", ], pluginFor: ["soong_build"], } Loading android/apex.go +64 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ package android import "sync" // ApexModule is the interface that a module type is expected to implement if // the module has to be built differently depending on whether the module // is destined for an apex or not (installed to one of the regular partitions). Loading Loading @@ -94,6 +96,68 @@ func (m *ApexModuleBase) IsInstallableToApex() bool { return false } // This structure maps a module name to the set of APEX bundle names that the module // should be built for. Examples: // // ...["foo"]["bar"] == true: module foo is directly depended on by APEX bar // ...["foo"]["bar"] == false: module foo is indirectly depended on by APEX bar // ...["foo"]["bar"] doesn't exist: foo is not built for APEX bar // ...["foo"] doesn't exist: foo is not built for any APEX func apexBundleNamesMap(config Config) map[string]map[string]bool { return config.Once("apexBundleNames", func() interface{} { return make(map[string]map[string]bool) }).(map[string]map[string]bool) } var bundleNamesMapMutex sync.Mutex // Mark that a module named moduleName should be built for an apex named bundleName // directDep should be set to true if the module is a direct dependency of the apex. func BuildModuleForApexBundle(ctx BaseModuleContext, moduleName string, bundleName string, directDep bool) { bundleNamesMapMutex.Lock() defer bundleNamesMapMutex.Unlock() bundleNames, ok := apexBundleNamesMap(ctx.Config())[moduleName] if !ok { bundleNames = make(map[string]bool) apexBundleNamesMap(ctx.Config())[moduleName] = bundleNames } bundleNames[bundleName] = bundleNames[bundleName] || directDep } // Returns the list of apex bundle names that the module named moduleName // should be built for. func GetApexBundlesForModule(ctx BaseModuleContext, moduleName string) map[string]bool { bundleNamesMapMutex.Lock() defer bundleNamesMapMutex.Unlock() return apexBundleNamesMap(ctx.Config())[moduleName] } // Tests if moduleName is directly depended on by bundleName (i.e. referenced in // native_shared_libs, etc.) func DirectlyInApex(config Config, bundleName string, moduleName string) bool { bundleNamesMapMutex.Lock() defer bundleNamesMapMutex.Unlock() if bundleNames, ok := apexBundleNamesMap(config)[moduleName]; ok { return bundleNames[bundleName] } return false } // Tests if moduleName is directly depended on by any APEX. If this returns true, // that means the module is part of the platform. func DirectlyInAnyApex(config Config, moduleName string) bool { bundleNamesMapMutex.Lock() defer bundleNamesMapMutex.Unlock() if bundleNames, ok := apexBundleNamesMap(config)[moduleName]; ok { for bn := range bundleNames { if bundleNames[bn] { return true } } } return false } func InitApexModule(m ApexModule) { base := m.apexModuleBase() base.canHaveApexVariants = true Loading apex/apex.go +8 −14 Original line number Diff line number Diff line Loading @@ -128,13 +128,6 @@ func init() { }) } // maps a module name to set of apex bundle names that the module should be built for func apexBundleNamesFor(config android.Config) map[string]map[string]bool { return config.Once("apexBundleNames", func() interface{} { return make(map[string]map[string]bool) }).(map[string]map[string]bool) } // Mark the direct and transitive dependencies of apex bundles so that they // can be built for the apex bundles. func apexDepsMutator(mctx android.TopDownMutatorContext) { Loading @@ -143,12 +136,9 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) { mctx.WalkDeps(func(child, parent android.Module) bool { if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() { moduleName := mctx.OtherModuleName(am) + "-" + am.Target().String() bundleNames, ok := apexBundleNamesFor(mctx.Config())[moduleName] if !ok { bundleNames = make(map[string]bool) apexBundleNamesFor(mctx.Config())[moduleName] = bundleNames } bundleNames[apexBundleName] = true // If the parent is apexBundle, this child is directly depended. _, directDep := parent.(*apexBundle) android.BuildModuleForApexBundle(mctx, moduleName, apexBundleName, directDep) return true } else { return false Loading @@ -161,7 +151,8 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) { func apexMutator(mctx android.BottomUpMutatorContext) { if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() { moduleName := mctx.ModuleName() + "-" + am.Target().String() if bundleNames, ok := apexBundleNamesFor(mctx.Config())[moduleName]; ok { bundleNames := android.GetApexBundlesForModule(mctx, moduleName) if len(bundleNames) > 0 { variations := []string{"platform"} for bn := range bundleNames { variations = append(variations, bn) Loading Loading @@ -495,6 +486,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { // indirect dependencies if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && am.IsInstallableToApex() { if cc, ok := child.(*cc.Module); ok { if cc.IsStubs() || cc.HasStubsVariants() { return false } depName := ctx.OtherModuleName(child) fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc) filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib}) Loading apex/apex_test.go 0 → 100644 +369 −0 Original line number Diff line number Diff line // 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 ( "android/soong/android" "android/soong/cc" "io/ioutil" "os" "strings" "testing" ) func testApex(t *testing.T, bp string) *android.TestContext { config, buildDir := setup(t) defer teardown(buildDir) ctx := android.NewTestArchContext() ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apexBundleFactory)) ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apexKeyFactory)) ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.TopDown("apex_deps", apexDepsMutator) ctx.BottomUp("apex", apexMutator) }) ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory)) ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(cc.LibrarySharedFactory)) ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory)) ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory)) ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("link", cc.LinkageMutator).Parallel() ctx.BottomUp("version", cc.VersionMutator).Parallel() ctx.BottomUp("begin", cc.BeginMutator).Parallel() }) ctx.Register() bp = bp + ` toolchain_library { name: "libcompiler_rt-extras", src: "", } toolchain_library { name: "libatomic", src: "", } toolchain_library { name: "libgcc", src: "", } toolchain_library { name: "libclang_rt.builtins-aarch64-android", src: "", } toolchain_library { name: "libclang_rt.builtins-arm-android", src: "", } cc_object { name: "crtbegin_so", stl: "none", } cc_object { name: "crtend_so", stl: "none", } ` ctx.MockFileSystem(map[string][]byte{ "Android.bp": []byte(bp), "testkey.avbpubkey": nil, "testkey.pem": nil, "build/target/product/security": nil, "apex_manifest.json": nil, "system/sepolicy/apex/myapex-file_contexts": nil, "mylib.cpp": nil, }) _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) android.FailIfErrored(t, errs) _, errs = ctx.PrepareBuildActions(config) android.FailIfErrored(t, errs) return ctx } func setup(t *testing.T) (config android.Config, buildDir string) { buildDir, err := ioutil.TempDir("", "soong_apex_test") if err != nil { t.Fatal(err) } config = android.TestArchConfig(buildDir, nil) return } func teardown(buildDir string) { os.RemoveAll(buildDir) } // ensure that 'result' contains 'expected' func ensureContains(t *testing.T, result string, expected string) { if !strings.Contains(result, expected) { t.Errorf("%q is not found in %q", expected, result) } } // ensures that 'result' does not contain 'notExpected' func ensureNotContains(t *testing.T, result string, notExpected string) { if strings.Contains(result, notExpected) { t.Errorf("%q is found in %q", notExpected, result) } } func ensureListContains(t *testing.T, result []string, expected string) { if !android.InList(expected, result) { t.Errorf("%q is not found in %v", expected, result) } } func ensureListNotContains(t *testing.T, result []string, notExpected string) { if android.InList(notExpected, result) { t.Errorf("%q is found in %v", notExpected, result) } } // Minimal test func TestBasicApex(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library { name: "mylib", srcs: ["mylib.cpp"], shared_libs: ["mylib2"], system_shared_libs: [], stl: "none", } cc_library { name: "mylib2", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", } `) apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that main rule creates an output ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned") // Ensure that apex variant is created for the direct dep ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex") // Ensure that apex variant is created for the indirect dep ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image/lib64/mylib.so") ensureContains(t, copyCmds, "image/lib64/mylib2.so") } func TestApexWithStubs(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib", "mylib3"], } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library { name: "mylib", srcs: ["mylib.cpp"], shared_libs: ["mylib2", "mylib3"], system_shared_libs: [], stl: "none", } cc_library { name: "mylib2", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", stubs: { versions: ["1", "2", "3"], }, } cc_library { name: "mylib3", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", stubs: { versions: ["10", "11", "12"], }, } `) apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included ensureContains(t, copyCmds, "image/lib64/mylib.so") // Ensure that indirect stubs dep is not included ensureNotContains(t, copyCmds, "image/lib64/mylib2.so") // Ensure that direct stubs dep is included ensureContains(t, copyCmds, "image/lib64/mylib3.so") mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"] // Ensure that mylib is linking with the latest version of stubs for mylib2 ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_3_myapex/mylib2.so") // ... and not linking to the non-stub (impl) variant of mylib2 ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_myapex/mylib2.so") // Ensure that mylib is linking with the non-stub (impl) of mylib3 (because mylib3 is in the same apex) ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_myapex/mylib3.so") // .. and not linking to the stubs variant of mylib3 ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12_myapex/mylib3.so") } func TestApexWithSystemLibsStubs(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib", "mylib_shared", "libdl", "libm"], } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library { name: "mylib", srcs: ["mylib.cpp"], shared_libs: ["libdl#27"], stl: "none", } cc_library_shared { name: "mylib_shared", srcs: ["mylib.cpp"], shared_libs: ["libdl#27"], stl: "none", } cc_library { name: "libc", no_libgcc: true, nocrt: true, system_shared_libs: [], stl: "none", stubs: { versions: ["27", "28", "29"], }, } cc_library { name: "libm", no_libgcc: true, nocrt: true, system_shared_libs: [], stl: "none", stubs: { versions: ["27", "28", "29"], }, } cc_library { name: "libdl", no_libgcc: true, nocrt: true, system_shared_libs: [], stl: "none", stubs: { versions: ["27", "28", "29"], }, } `) apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that mylib, libm, libdl are included. ensureContains(t, copyCmds, "image/lib64/mylib.so") ensureContains(t, copyCmds, "image/lib64/libm.so") ensureContains(t, copyCmds, "image/lib64/libdl.so") // Ensure that libc is not included (since it has stubs and not listed in native_shared_libs) ensureNotContains(t, copyCmds, "image/lib64/libc.so") mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"] mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_shared_myapex").Rule("cc").Args["cFlags"] // 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_myapex/libc.so") // ... and not linking to the non-stub (impl) variant ensureNotContains(t, mylibLdFlags, "libc/android_arm64_armv8-a_shared_myapex/libc.so") // ... Cflags from stub is correctly exported to mylib ensureContains(t, mylibCFlags, "__LIBC_API__=29") ensureContains(t, mylibSharedCFlags, "__LIBC_API__=29") // For dependency to libm // Ensure that mylib is linking with the non-stub (impl) variant ensureContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_myapex/libm.so") // ... and not linking to the stub variant ensureNotContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_29_myapex/libm.so") // ... and is not compiling with the stub ensureNotContains(t, mylibCFlags, "__LIBM_API__=29") ensureNotContains(t, mylibSharedCFlags, "__LIBM_API__=29") // For dependency to libdl // Ensure that mylib is linking with the specified version of stubs ensureContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_27_myapex/libdl.so") // ... and not linking to the other versions of stubs ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_28_myapex/libdl.so") ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_29_myapex/libdl.so") // ... and not linking to the non-stub (impl) variant ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_myapex/libdl.so") // ... Cflags from stub is correctly exported to mylib ensureContains(t, mylibCFlags, "__LIBDL_API__=27") ensureContains(t, mylibSharedCFlags, "__LIBDL_API__=27") } cc/cc.go +96 −16 Original line number Diff line number Diff line Loading @@ -39,7 +39,7 @@ func init() { ctx.BottomUp("vndk", vndkMutator).Parallel() ctx.BottomUp("ndk_api", ndkApiMutator).Parallel() ctx.BottomUp("test_per_src", testPerSrcMutator).Parallel() ctx.BottomUp("version", versionMutator).Parallel() ctx.BottomUp("version", VersionMutator).Parallel() ctx.BottomUp("begin", BeginMutator).Parallel() }) Loading Loading @@ -248,6 +248,7 @@ type ModuleContextIntf interface { getVndkExtendsModuleName() string isPgoCompile() bool useClangLld(actx ModuleContext) bool isApex() bool } type ModuleContext interface { Loading Loading @@ -308,6 +309,8 @@ type dependencyTag struct { library bool reexportFlags bool explicitlyVersioned bool } var ( Loading Loading @@ -511,6 +514,20 @@ func (c *Module) onlyInRecovery() bool { return c.ModuleBase.InstallInRecovery() } func (c *Module) IsStubs() bool { if library, ok := c.linker.(*libraryDecorator); ok { return library.buildStubs() } return false } func (c *Module) HasStubsVariants() bool { if library, ok := c.linker.(*libraryDecorator); ok { return len(library.Properties.Stubs.Versions) > 0 } return false } type baseModuleContext struct { android.BaseContext moduleContextImpl Loading Loading @@ -649,6 +666,11 @@ func (ctx *moduleContextImpl) getVndkExtendsModuleName() string { return ctx.mod.getVndkExtendsModuleName() } // Tests if this module is built for APEX func (ctx *moduleContextImpl) isApex() bool { return ctx.mod.ApexName() != "" } func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module { return &Module{ hod: hod, Loading Loading @@ -1081,6 +1103,30 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { {Mutator: "link", Variation: "static"}, }, lateStaticDepTag, deps.LateStaticLibs...) addSharedLibDependencies := func(depTag dependencyTag, name string, version string) { var variations []blueprint.Variation variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"}) versionVariantAvail := ctx.Os() == android.Android && !ctx.useVndk() && !c.inRecovery() if version != "" && versionVariantAvail { // Version is explicitly specified. i.e. libFoo#30 variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version}) depTag.explicitlyVersioned = true } actx.AddVariationDependencies(variations, depTag, name) // If the version is not specified, add dependency to the latest stubs library. // The stubs library will be used when the depending module is built for APEX and // the dependent module is not in the same APEX. latestVersion := latestStubsVersionFor(actx.Config(), name) if version == "" && latestVersion != "" && versionVariantAvail { actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "shared"}, {Mutator: "version", Variation: latestVersion}, }, depTag, name) // Note that depTag.explicitlyVersioned is false in this case. } } // shared lib names without the #version suffix var sharedLibNames []string Loading @@ -1091,29 +1137,17 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { if inList(lib, deps.ReexportSharedLibHeaders) { depTag = sharedExportDepTag } var variations []blueprint.Variation variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"}) if version != "" && ctx.Os() == android.Android && !ctx.useVndk() && !c.inRecovery() { variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version}) } actx.AddVariationDependencies(variations, depTag, name) addSharedLibDependencies(depTag, name, version) } for _, lib := range deps.LateSharedLibs { name, version := stubsLibNameAndVersion(lib) if inList(name, sharedLibNames) { if inList(lib, sharedLibNames) { // This is to handle the case that some of the late shared libs (libc, libdl, libm, ...) // are added also to SharedLibs with version (e.g., libc#10). If not skipped, we will be // linking against both the stubs lib and the non-stubs lib at the same time. continue } depTag := lateSharedDepTag var variations []blueprint.Variation variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"}) if version != "" && ctx.Os() == android.Android && !ctx.useVndk() && !c.inRecovery() { variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version}) } actx.AddVariationDependencies(variations, depTag, name) addSharedLibDependencies(lateSharedDepTag, lib, "") } actx.AddVariationDependencies([]blueprint.Variation{ Loading Loading @@ -1372,7 +1406,53 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return } } // Extract explicitlyVersioned field from the depTag and reset it inside the struct. // Otherwise, sharedDepTag and lateSharedDepTag with explicitlyVersioned set to true // won't be matched to sharedDepTag and lateSharedDepTag. explicitlyVersioned := false if t, ok := depTag.(dependencyTag); ok { explicitlyVersioned = t.explicitlyVersioned t.explicitlyVersioned = false depTag = t } if t, ok := depTag.(dependencyTag); ok && t.library { if dependentLibrary, ok := ccDep.linker.(*libraryDecorator); ok { depIsStubs := dependentLibrary.buildStubs() depHasStubs := ccDep.HasStubsVariants() depNameWithTarget := depName + "-" + ccDep.Target().String() depInSameApex := android.DirectlyInApex(ctx.Config(), c.ApexName(), depNameWithTarget) depInPlatform := !android.DirectlyInAnyApex(ctx.Config(), depNameWithTarget) var useThisDep bool if depIsStubs && explicitlyVersioned { // Always respect dependency to the versioned stubs (i.e. libX#10) useThisDep = true } else if !depHasStubs { // Use non-stub variant if that is the only choice // (i.e. depending on a lib without stubs.version property) useThisDep = true } else if c.IsForPlatform() { // If not building for APEX, use stubs only when it is from // an APEX (and not from platform) useThisDep = (depInPlatform != depIsStubs) if c.inRecovery() { // However, for recovery modules, since there is no APEX there, // always link to non-stub variant useThisDep = !depIsStubs } } else { // If building for APEX, use stubs only when it is not from // the same APEX useThisDep = (depInSameApex != depIsStubs) } if !useThisDep { return // stop processing this dep } } if i, ok := ccDep.linker.(exportedFlagsProducer); ok { flags := i.exportedFlags() deps := i.exportedFlagsDeps() Loading Loading
Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -353,6 +353,9 @@ bootstrap_go_package { "apex/apex.go", "apex/key.go", ], testSrcs: [ "apex/apex_test.go", ], pluginFor: ["soong_build"], } Loading
android/apex.go +64 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ package android import "sync" // ApexModule is the interface that a module type is expected to implement if // the module has to be built differently depending on whether the module // is destined for an apex or not (installed to one of the regular partitions). Loading Loading @@ -94,6 +96,68 @@ func (m *ApexModuleBase) IsInstallableToApex() bool { return false } // This structure maps a module name to the set of APEX bundle names that the module // should be built for. Examples: // // ...["foo"]["bar"] == true: module foo is directly depended on by APEX bar // ...["foo"]["bar"] == false: module foo is indirectly depended on by APEX bar // ...["foo"]["bar"] doesn't exist: foo is not built for APEX bar // ...["foo"] doesn't exist: foo is not built for any APEX func apexBundleNamesMap(config Config) map[string]map[string]bool { return config.Once("apexBundleNames", func() interface{} { return make(map[string]map[string]bool) }).(map[string]map[string]bool) } var bundleNamesMapMutex sync.Mutex // Mark that a module named moduleName should be built for an apex named bundleName // directDep should be set to true if the module is a direct dependency of the apex. func BuildModuleForApexBundle(ctx BaseModuleContext, moduleName string, bundleName string, directDep bool) { bundleNamesMapMutex.Lock() defer bundleNamesMapMutex.Unlock() bundleNames, ok := apexBundleNamesMap(ctx.Config())[moduleName] if !ok { bundleNames = make(map[string]bool) apexBundleNamesMap(ctx.Config())[moduleName] = bundleNames } bundleNames[bundleName] = bundleNames[bundleName] || directDep } // Returns the list of apex bundle names that the module named moduleName // should be built for. func GetApexBundlesForModule(ctx BaseModuleContext, moduleName string) map[string]bool { bundleNamesMapMutex.Lock() defer bundleNamesMapMutex.Unlock() return apexBundleNamesMap(ctx.Config())[moduleName] } // Tests if moduleName is directly depended on by bundleName (i.e. referenced in // native_shared_libs, etc.) func DirectlyInApex(config Config, bundleName string, moduleName string) bool { bundleNamesMapMutex.Lock() defer bundleNamesMapMutex.Unlock() if bundleNames, ok := apexBundleNamesMap(config)[moduleName]; ok { return bundleNames[bundleName] } return false } // Tests if moduleName is directly depended on by any APEX. If this returns true, // that means the module is part of the platform. func DirectlyInAnyApex(config Config, moduleName string) bool { bundleNamesMapMutex.Lock() defer bundleNamesMapMutex.Unlock() if bundleNames, ok := apexBundleNamesMap(config)[moduleName]; ok { for bn := range bundleNames { if bundleNames[bn] { return true } } } return false } func InitApexModule(m ApexModule) { base := m.apexModuleBase() base.canHaveApexVariants = true Loading
apex/apex.go +8 −14 Original line number Diff line number Diff line Loading @@ -128,13 +128,6 @@ func init() { }) } // maps a module name to set of apex bundle names that the module should be built for func apexBundleNamesFor(config android.Config) map[string]map[string]bool { return config.Once("apexBundleNames", func() interface{} { return make(map[string]map[string]bool) }).(map[string]map[string]bool) } // Mark the direct and transitive dependencies of apex bundles so that they // can be built for the apex bundles. func apexDepsMutator(mctx android.TopDownMutatorContext) { Loading @@ -143,12 +136,9 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) { mctx.WalkDeps(func(child, parent android.Module) bool { if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() { moduleName := mctx.OtherModuleName(am) + "-" + am.Target().String() bundleNames, ok := apexBundleNamesFor(mctx.Config())[moduleName] if !ok { bundleNames = make(map[string]bool) apexBundleNamesFor(mctx.Config())[moduleName] = bundleNames } bundleNames[apexBundleName] = true // If the parent is apexBundle, this child is directly depended. _, directDep := parent.(*apexBundle) android.BuildModuleForApexBundle(mctx, moduleName, apexBundleName, directDep) return true } else { return false Loading @@ -161,7 +151,8 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) { func apexMutator(mctx android.BottomUpMutatorContext) { if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() { moduleName := mctx.ModuleName() + "-" + am.Target().String() if bundleNames, ok := apexBundleNamesFor(mctx.Config())[moduleName]; ok { bundleNames := android.GetApexBundlesForModule(mctx, moduleName) if len(bundleNames) > 0 { variations := []string{"platform"} for bn := range bundleNames { variations = append(variations, bn) Loading Loading @@ -495,6 +486,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { // indirect dependencies if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && am.IsInstallableToApex() { if cc, ok := child.(*cc.Module); ok { if cc.IsStubs() || cc.HasStubsVariants() { return false } depName := ctx.OtherModuleName(child) fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc) filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib}) Loading
apex/apex_test.go 0 → 100644 +369 −0 Original line number Diff line number Diff line // 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 ( "android/soong/android" "android/soong/cc" "io/ioutil" "os" "strings" "testing" ) func testApex(t *testing.T, bp string) *android.TestContext { config, buildDir := setup(t) defer teardown(buildDir) ctx := android.NewTestArchContext() ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apexBundleFactory)) ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apexKeyFactory)) ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.TopDown("apex_deps", apexDepsMutator) ctx.BottomUp("apex", apexMutator) }) ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory)) ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(cc.LibrarySharedFactory)) ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory)) ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory)) ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("link", cc.LinkageMutator).Parallel() ctx.BottomUp("version", cc.VersionMutator).Parallel() ctx.BottomUp("begin", cc.BeginMutator).Parallel() }) ctx.Register() bp = bp + ` toolchain_library { name: "libcompiler_rt-extras", src: "", } toolchain_library { name: "libatomic", src: "", } toolchain_library { name: "libgcc", src: "", } toolchain_library { name: "libclang_rt.builtins-aarch64-android", src: "", } toolchain_library { name: "libclang_rt.builtins-arm-android", src: "", } cc_object { name: "crtbegin_so", stl: "none", } cc_object { name: "crtend_so", stl: "none", } ` ctx.MockFileSystem(map[string][]byte{ "Android.bp": []byte(bp), "testkey.avbpubkey": nil, "testkey.pem": nil, "build/target/product/security": nil, "apex_manifest.json": nil, "system/sepolicy/apex/myapex-file_contexts": nil, "mylib.cpp": nil, }) _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) android.FailIfErrored(t, errs) _, errs = ctx.PrepareBuildActions(config) android.FailIfErrored(t, errs) return ctx } func setup(t *testing.T) (config android.Config, buildDir string) { buildDir, err := ioutil.TempDir("", "soong_apex_test") if err != nil { t.Fatal(err) } config = android.TestArchConfig(buildDir, nil) return } func teardown(buildDir string) { os.RemoveAll(buildDir) } // ensure that 'result' contains 'expected' func ensureContains(t *testing.T, result string, expected string) { if !strings.Contains(result, expected) { t.Errorf("%q is not found in %q", expected, result) } } // ensures that 'result' does not contain 'notExpected' func ensureNotContains(t *testing.T, result string, notExpected string) { if strings.Contains(result, notExpected) { t.Errorf("%q is found in %q", notExpected, result) } } func ensureListContains(t *testing.T, result []string, expected string) { if !android.InList(expected, result) { t.Errorf("%q is not found in %v", expected, result) } } func ensureListNotContains(t *testing.T, result []string, notExpected string) { if android.InList(notExpected, result) { t.Errorf("%q is found in %v", notExpected, result) } } // Minimal test func TestBasicApex(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library { name: "mylib", srcs: ["mylib.cpp"], shared_libs: ["mylib2"], system_shared_libs: [], stl: "none", } cc_library { name: "mylib2", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", } `) apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that main rule creates an output ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned") // Ensure that apex variant is created for the direct dep ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex") // Ensure that apex variant is created for the indirect dep ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image/lib64/mylib.so") ensureContains(t, copyCmds, "image/lib64/mylib2.so") } func TestApexWithStubs(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib", "mylib3"], } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library { name: "mylib", srcs: ["mylib.cpp"], shared_libs: ["mylib2", "mylib3"], system_shared_libs: [], stl: "none", } cc_library { name: "mylib2", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", stubs: { versions: ["1", "2", "3"], }, } cc_library { name: "mylib3", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", stubs: { versions: ["10", "11", "12"], }, } `) apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included ensureContains(t, copyCmds, "image/lib64/mylib.so") // Ensure that indirect stubs dep is not included ensureNotContains(t, copyCmds, "image/lib64/mylib2.so") // Ensure that direct stubs dep is included ensureContains(t, copyCmds, "image/lib64/mylib3.so") mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"] // Ensure that mylib is linking with the latest version of stubs for mylib2 ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_3_myapex/mylib2.so") // ... and not linking to the non-stub (impl) variant of mylib2 ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_myapex/mylib2.so") // Ensure that mylib is linking with the non-stub (impl) of mylib3 (because mylib3 is in the same apex) ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_myapex/mylib3.so") // .. and not linking to the stubs variant of mylib3 ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12_myapex/mylib3.so") } func TestApexWithSystemLibsStubs(t *testing.T) { ctx := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib", "mylib_shared", "libdl", "libm"], } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library { name: "mylib", srcs: ["mylib.cpp"], shared_libs: ["libdl#27"], stl: "none", } cc_library_shared { name: "mylib_shared", srcs: ["mylib.cpp"], shared_libs: ["libdl#27"], stl: "none", } cc_library { name: "libc", no_libgcc: true, nocrt: true, system_shared_libs: [], stl: "none", stubs: { versions: ["27", "28", "29"], }, } cc_library { name: "libm", no_libgcc: true, nocrt: true, system_shared_libs: [], stl: "none", stubs: { versions: ["27", "28", "29"], }, } cc_library { name: "libdl", no_libgcc: true, nocrt: true, system_shared_libs: [], stl: "none", stubs: { versions: ["27", "28", "29"], }, } `) apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that mylib, libm, libdl are included. ensureContains(t, copyCmds, "image/lib64/mylib.so") ensureContains(t, copyCmds, "image/lib64/libm.so") ensureContains(t, copyCmds, "image/lib64/libdl.so") // Ensure that libc is not included (since it has stubs and not listed in native_shared_libs) ensureNotContains(t, copyCmds, "image/lib64/libc.so") mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"] mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_shared_myapex").Rule("cc").Args["cFlags"] // 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_myapex/libc.so") // ... and not linking to the non-stub (impl) variant ensureNotContains(t, mylibLdFlags, "libc/android_arm64_armv8-a_shared_myapex/libc.so") // ... Cflags from stub is correctly exported to mylib ensureContains(t, mylibCFlags, "__LIBC_API__=29") ensureContains(t, mylibSharedCFlags, "__LIBC_API__=29") // For dependency to libm // Ensure that mylib is linking with the non-stub (impl) variant ensureContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_myapex/libm.so") // ... and not linking to the stub variant ensureNotContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_29_myapex/libm.so") // ... and is not compiling with the stub ensureNotContains(t, mylibCFlags, "__LIBM_API__=29") ensureNotContains(t, mylibSharedCFlags, "__LIBM_API__=29") // For dependency to libdl // Ensure that mylib is linking with the specified version of stubs ensureContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_27_myapex/libdl.so") // ... and not linking to the other versions of stubs ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_28_myapex/libdl.so") ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_29_myapex/libdl.so") // ... and not linking to the non-stub (impl) variant ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_myapex/libdl.so") // ... Cflags from stub is correctly exported to mylib ensureContains(t, mylibCFlags, "__LIBDL_API__=27") ensureContains(t, mylibSharedCFlags, "__LIBDL_API__=27") }
cc/cc.go +96 −16 Original line number Diff line number Diff line Loading @@ -39,7 +39,7 @@ func init() { ctx.BottomUp("vndk", vndkMutator).Parallel() ctx.BottomUp("ndk_api", ndkApiMutator).Parallel() ctx.BottomUp("test_per_src", testPerSrcMutator).Parallel() ctx.BottomUp("version", versionMutator).Parallel() ctx.BottomUp("version", VersionMutator).Parallel() ctx.BottomUp("begin", BeginMutator).Parallel() }) Loading Loading @@ -248,6 +248,7 @@ type ModuleContextIntf interface { getVndkExtendsModuleName() string isPgoCompile() bool useClangLld(actx ModuleContext) bool isApex() bool } type ModuleContext interface { Loading Loading @@ -308,6 +309,8 @@ type dependencyTag struct { library bool reexportFlags bool explicitlyVersioned bool } var ( Loading Loading @@ -511,6 +514,20 @@ func (c *Module) onlyInRecovery() bool { return c.ModuleBase.InstallInRecovery() } func (c *Module) IsStubs() bool { if library, ok := c.linker.(*libraryDecorator); ok { return library.buildStubs() } return false } func (c *Module) HasStubsVariants() bool { if library, ok := c.linker.(*libraryDecorator); ok { return len(library.Properties.Stubs.Versions) > 0 } return false } type baseModuleContext struct { android.BaseContext moduleContextImpl Loading Loading @@ -649,6 +666,11 @@ func (ctx *moduleContextImpl) getVndkExtendsModuleName() string { return ctx.mod.getVndkExtendsModuleName() } // Tests if this module is built for APEX func (ctx *moduleContextImpl) isApex() bool { return ctx.mod.ApexName() != "" } func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module { return &Module{ hod: hod, Loading Loading @@ -1081,6 +1103,30 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { {Mutator: "link", Variation: "static"}, }, lateStaticDepTag, deps.LateStaticLibs...) addSharedLibDependencies := func(depTag dependencyTag, name string, version string) { var variations []blueprint.Variation variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"}) versionVariantAvail := ctx.Os() == android.Android && !ctx.useVndk() && !c.inRecovery() if version != "" && versionVariantAvail { // Version is explicitly specified. i.e. libFoo#30 variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version}) depTag.explicitlyVersioned = true } actx.AddVariationDependencies(variations, depTag, name) // If the version is not specified, add dependency to the latest stubs library. // The stubs library will be used when the depending module is built for APEX and // the dependent module is not in the same APEX. latestVersion := latestStubsVersionFor(actx.Config(), name) if version == "" && latestVersion != "" && versionVariantAvail { actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "shared"}, {Mutator: "version", Variation: latestVersion}, }, depTag, name) // Note that depTag.explicitlyVersioned is false in this case. } } // shared lib names without the #version suffix var sharedLibNames []string Loading @@ -1091,29 +1137,17 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { if inList(lib, deps.ReexportSharedLibHeaders) { depTag = sharedExportDepTag } var variations []blueprint.Variation variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"}) if version != "" && ctx.Os() == android.Android && !ctx.useVndk() && !c.inRecovery() { variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version}) } actx.AddVariationDependencies(variations, depTag, name) addSharedLibDependencies(depTag, name, version) } for _, lib := range deps.LateSharedLibs { name, version := stubsLibNameAndVersion(lib) if inList(name, sharedLibNames) { if inList(lib, sharedLibNames) { // This is to handle the case that some of the late shared libs (libc, libdl, libm, ...) // are added also to SharedLibs with version (e.g., libc#10). If not skipped, we will be // linking against both the stubs lib and the non-stubs lib at the same time. continue } depTag := lateSharedDepTag var variations []blueprint.Variation variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"}) if version != "" && ctx.Os() == android.Android && !ctx.useVndk() && !c.inRecovery() { variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version}) } actx.AddVariationDependencies(variations, depTag, name) addSharedLibDependencies(lateSharedDepTag, lib, "") } actx.AddVariationDependencies([]blueprint.Variation{ Loading Loading @@ -1372,7 +1406,53 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return } } // Extract explicitlyVersioned field from the depTag and reset it inside the struct. // Otherwise, sharedDepTag and lateSharedDepTag with explicitlyVersioned set to true // won't be matched to sharedDepTag and lateSharedDepTag. explicitlyVersioned := false if t, ok := depTag.(dependencyTag); ok { explicitlyVersioned = t.explicitlyVersioned t.explicitlyVersioned = false depTag = t } if t, ok := depTag.(dependencyTag); ok && t.library { if dependentLibrary, ok := ccDep.linker.(*libraryDecorator); ok { depIsStubs := dependentLibrary.buildStubs() depHasStubs := ccDep.HasStubsVariants() depNameWithTarget := depName + "-" + ccDep.Target().String() depInSameApex := android.DirectlyInApex(ctx.Config(), c.ApexName(), depNameWithTarget) depInPlatform := !android.DirectlyInAnyApex(ctx.Config(), depNameWithTarget) var useThisDep bool if depIsStubs && explicitlyVersioned { // Always respect dependency to the versioned stubs (i.e. libX#10) useThisDep = true } else if !depHasStubs { // Use non-stub variant if that is the only choice // (i.e. depending on a lib without stubs.version property) useThisDep = true } else if c.IsForPlatform() { // If not building for APEX, use stubs only when it is from // an APEX (and not from platform) useThisDep = (depInPlatform != depIsStubs) if c.inRecovery() { // However, for recovery modules, since there is no APEX there, // always link to non-stub variant useThisDep = !depIsStubs } } else { // If building for APEX, use stubs only when it is not from // the same APEX useThisDep = (depInSameApex != depIsStubs) } if !useThisDep { return // stop processing this dep } } if i, ok := ccDep.linker.(exportedFlagsProducer); ok { flags := i.exportedFlags() deps := i.exportedFlagsDeps() Loading