Add "provide_cpp_shared_libs/uses" props to "apex"
For APEXes to share C++ native libraries, we need a new kind of depedency between APEXes: "providing" APEXes and "using" APEXes. To reflect this dependency two new properties are added. provide_cpp_shared_libs: bool this indicates that the current APEX module provides the native C++ shared libs to other APEXes. uses: []string this indicates that the current APEX module uses the native C++ shared libraries from APEXes listed. With these two, "using" APEXes can omit shared libraries in its APEX bundle and use them from the "providing" APEXes. Note that without corresponding changes in ld.config.txt, this won't work.(The linker namespaces should be configured so that user APEX can access provided libs.) Bug: 136975105 Test: m nothing (this will trigger soong's test) Change-Id: Iec6f9f67bcbde01145acc383f862ba21c8197536
This commit is contained in:
42
apex/apex.go
42
apex/apex.go
@@ -111,6 +111,7 @@ var (
|
|||||||
testTag = dependencyTag{name: "test"}
|
testTag = dependencyTag{name: "test"}
|
||||||
keyTag = dependencyTag{name: "key"}
|
keyTag = dependencyTag{name: "key"}
|
||||||
certificateTag = dependencyTag{name: "certificate"}
|
certificateTag = dependencyTag{name: "certificate"}
|
||||||
|
usesTag = dependencyTag{name: "uses"}
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -147,6 +148,7 @@ func init() {
|
|||||||
android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
||||||
ctx.TopDown("apex_deps", apexDepsMutator)
|
ctx.TopDown("apex_deps", apexDepsMutator)
|
||||||
ctx.BottomUp("apex", apexMutator).Parallel()
|
ctx.BottomUp("apex", apexMutator).Parallel()
|
||||||
|
ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,6 +189,11 @@ func apexMutator(mctx android.BottomUpMutatorContext) {
|
|||||||
mctx.CreateVariations(apexBundleName)
|
mctx.CreateVariations(apexBundleName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func apexUsesMutator(mctx android.BottomUpMutatorContext) {
|
||||||
|
if ab, ok := mctx.Module().(*apexBundle); ok {
|
||||||
|
mctx.AddFarVariationDependencies(nil, usesTag, ab.properties.Uses...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type apexNativeDependencies struct {
|
type apexNativeDependencies struct {
|
||||||
// List of native libraries
|
// List of native libraries
|
||||||
@@ -272,6 +279,12 @@ type apexBundleProperties struct {
|
|||||||
|
|
||||||
// List of sanitizer names that this APEX is enabled for
|
// List of sanitizer names that this APEX is enabled for
|
||||||
SanitizerNames []string `blueprint:"mutated"`
|
SanitizerNames []string `blueprint:"mutated"`
|
||||||
|
|
||||||
|
// Indicates this APEX provides C++ shared libaries to other APEXes. Default: false.
|
||||||
|
Provide_cpp_shared_libs *bool
|
||||||
|
|
||||||
|
// List of providing APEXes' names so that this APEX can depend on provided shared libraries.
|
||||||
|
Uses []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type apexTargetBundleProperties struct {
|
type apexTargetBundleProperties struct {
|
||||||
@@ -727,6 +740,30 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
|
|
||||||
handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
|
handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
|
||||||
|
|
||||||
|
// Check if "uses" requirements are met with dependent apexBundles
|
||||||
|
var providedNativeSharedLibs []string
|
||||||
|
useVendor := proptools.Bool(a.properties.Use_vendor)
|
||||||
|
ctx.VisitDirectDepsBlueprint(func(m blueprint.Module) {
|
||||||
|
if ctx.OtherModuleDependencyTag(m) != usesTag {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
otherName := ctx.OtherModuleName(m)
|
||||||
|
other, ok := m.(*apexBundle)
|
||||||
|
if !ok {
|
||||||
|
ctx.PropertyErrorf("uses", "%q is not a provider", otherName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if proptools.Bool(other.properties.Use_vendor) != useVendor {
|
||||||
|
ctx.PropertyErrorf("use_vendor", "%q has different value of use_vendor", otherName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !proptools.Bool(other.properties.Provide_cpp_shared_libs) {
|
||||||
|
ctx.PropertyErrorf("uses", "%q does not provide native_shared_libs", otherName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
providedNativeSharedLibs = append(providedNativeSharedLibs, other.properties.Native_shared_libs...)
|
||||||
|
})
|
||||||
|
|
||||||
ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
|
ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
|
||||||
if _, ok := parent.(*apexBundle); ok {
|
if _, ok := parent.(*apexBundle); ok {
|
||||||
// direct dependencies
|
// direct dependencies
|
||||||
@@ -815,6 +852,11 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
// indirect dependencies
|
// indirect dependencies
|
||||||
if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && am.IsInstallableToApex() {
|
if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && am.IsInstallableToApex() {
|
||||||
if cc, ok := child.(*cc.Module); ok {
|
if cc, ok := child.(*cc.Module); ok {
|
||||||
|
if android.InList(cc.Name(), providedNativeSharedLibs) {
|
||||||
|
// If we're using a shared library which is provided from other APEX,
|
||||||
|
// don't include it in this APEX
|
||||||
|
return false
|
||||||
|
}
|
||||||
if !a.Host() && (cc.IsStubs() || cc.HasStubsVariants()) {
|
if !a.Host() && (cc.IsStubs() || cc.HasStubsVariants()) {
|
||||||
// If the dependency is a stubs lib, don't include it in this APEX,
|
// If the dependency is a stubs lib, don't include it in this APEX,
|
||||||
// but make sure that the lib is installed on the device.
|
// but make sure that the lib is installed on the device.
|
||||||
|
@@ -29,7 +29,32 @@ import (
|
|||||||
|
|
||||||
var buildDir string
|
var buildDir string
|
||||||
|
|
||||||
|
func testApexError(t *testing.T, pattern, bp string) {
|
||||||
|
ctx, config := testApexContext(t, bp)
|
||||||
|
_, 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) *android.TestContext {
|
func testApex(t *testing.T, bp string) *android.TestContext {
|
||||||
|
ctx, config := testApexContext(t, bp)
|
||||||
|
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
|
||||||
|
android.FailIfErrored(t, errs)
|
||||||
|
_, errs = ctx.PrepareBuildActions(config)
|
||||||
|
android.FailIfErrored(t, errs)
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func testApexContext(t *testing.T, bp string) (*android.TestContext, android.Config) {
|
||||||
config := android.TestArchConfig(buildDir, nil)
|
config := android.TestArchConfig(buildDir, nil)
|
||||||
config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
|
config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
|
||||||
config.TestProductVariables.DefaultAppCertificate = proptools.StringPtr("vendor/foo/devkeys/test")
|
config.TestProductVariables.DefaultAppCertificate = proptools.StringPtr("vendor/foo/devkeys/test")
|
||||||
@@ -48,6 +73,7 @@ func testApex(t *testing.T, bp string) *android.TestContext {
|
|||||||
ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
||||||
ctx.TopDown("apex_deps", apexDepsMutator)
|
ctx.TopDown("apex_deps", apexDepsMutator)
|
||||||
ctx.BottomUp("apex", apexMutator)
|
ctx.BottomUp("apex", apexMutator)
|
||||||
|
ctx.BottomUp("apex_uses", apexUsesMutator)
|
||||||
ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel()
|
ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel()
|
||||||
ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel()
|
ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel()
|
||||||
})
|
})
|
||||||
@@ -168,8 +194,10 @@ func testApex(t *testing.T, bp string) *android.TestContext {
|
|||||||
"system/sepolicy/apex/myapex-file_contexts": nil,
|
"system/sepolicy/apex/myapex-file_contexts": nil,
|
||||||
"system/sepolicy/apex/myapex_keytest-file_contexts": nil,
|
"system/sepolicy/apex/myapex_keytest-file_contexts": nil,
|
||||||
"system/sepolicy/apex/otherapex-file_contexts": nil,
|
"system/sepolicy/apex/otherapex-file_contexts": nil,
|
||||||
|
"system/sepolicy/apex/commonapex-file_contexts": nil,
|
||||||
"mylib.cpp": nil,
|
"mylib.cpp": nil,
|
||||||
"mytest.cpp": nil,
|
"mytest.cpp": nil,
|
||||||
|
"mylib_common.cpp": nil,
|
||||||
"myprebuilt": nil,
|
"myprebuilt": nil,
|
||||||
"my_include": nil,
|
"my_include": nil,
|
||||||
"vendor/foo/devkeys/test.x509.pem": nil,
|
"vendor/foo/devkeys/test.x509.pem": nil,
|
||||||
@@ -188,12 +216,8 @@ func testApex(t *testing.T, bp string) *android.TestContext {
|
|||||||
"myapex-arm.apex": nil,
|
"myapex-arm.apex": nil,
|
||||||
"frameworks/base/api/current.txt": nil,
|
"frameworks/base/api/current.txt": nil,
|
||||||
})
|
})
|
||||||
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
|
|
||||||
android.FailIfErrored(t, errs)
|
|
||||||
_, errs = ctx.PrepareBuildActions(config)
|
|
||||||
android.FailIfErrored(t, errs)
|
|
||||||
|
|
||||||
return ctx
|
return ctx, config
|
||||||
}
|
}
|
||||||
|
|
||||||
func setUp() {
|
func setUp() {
|
||||||
@@ -210,6 +234,7 @@ func tearDown() {
|
|||||||
|
|
||||||
// ensure that 'result' contains 'expected'
|
// ensure that 'result' contains 'expected'
|
||||||
func ensureContains(t *testing.T, result string, expected string) {
|
func ensureContains(t *testing.T, result string, expected string) {
|
||||||
|
t.Helper()
|
||||||
if !strings.Contains(result, expected) {
|
if !strings.Contains(result, expected) {
|
||||||
t.Errorf("%q is not found in %q", expected, result)
|
t.Errorf("%q is not found in %q", expected, result)
|
||||||
}
|
}
|
||||||
@@ -217,18 +242,21 @@ func ensureContains(t *testing.T, result string, expected string) {
|
|||||||
|
|
||||||
// ensures that 'result' does not contain 'notExpected'
|
// ensures that 'result' does not contain 'notExpected'
|
||||||
func ensureNotContains(t *testing.T, result string, notExpected string) {
|
func ensureNotContains(t *testing.T, result string, notExpected string) {
|
||||||
|
t.Helper()
|
||||||
if strings.Contains(result, notExpected) {
|
if strings.Contains(result, notExpected) {
|
||||||
t.Errorf("%q is found in %q", notExpected, result)
|
t.Errorf("%q is found in %q", notExpected, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureListContains(t *testing.T, result []string, expected string) {
|
func ensureListContains(t *testing.T, result []string, expected string) {
|
||||||
|
t.Helper()
|
||||||
if !android.InList(expected, result) {
|
if !android.InList(expected, result) {
|
||||||
t.Errorf("%q is not found in %v", expected, result)
|
t.Errorf("%q is not found in %v", expected, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureListNotContains(t *testing.T, result []string, notExpected string) {
|
func ensureListNotContains(t *testing.T, result []string, notExpected string) {
|
||||||
|
t.Helper()
|
||||||
if android.InList(notExpected, result) {
|
if android.InList(notExpected, result) {
|
||||||
t.Errorf("%q is found in %v", notExpected, result)
|
t.Errorf("%q is found in %v", notExpected, result)
|
||||||
}
|
}
|
||||||
@@ -789,6 +817,30 @@ func TestUseVendor(t *testing.T) {
|
|||||||
ensureNotContains(t, inputsString, "android_arm64_armv8-a_core_shared_myapex/mylib2.so")
|
ensureNotContains(t, inputsString, "android_arm64_armv8-a_core_shared_myapex/mylib2.so")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 TestStaticLinking(t *testing.T) {
|
func TestStaticLinking(t *testing.T) {
|
||||||
ctx := testApex(t, `
|
ctx := testApex(t, `
|
||||||
apex {
|
apex {
|
||||||
@@ -1321,6 +1373,122 @@ func TestApexWithTests(t *testing.T) {
|
|||||||
ensureContains(t, copyCmds, "image.apex/bin/test/mytest")
|
ensureContains(t, copyCmds, "image.apex/bin/test/mytest")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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",
|
||||||
|
}
|
||||||
|
|
||||||
|
cc_library {
|
||||||
|
name: "libcommon",
|
||||||
|
srcs: ["mylib_common.cpp"],
|
||||||
|
system_shared_libs: [],
|
||||||
|
stl: "none",
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
module1 := ctx.ModuleForTests("myapex", "android_common_myapex")
|
||||||
|
apexRule1 := module1.Rule("apexRule")
|
||||||
|
copyCmds1 := apexRule1.Args["copy_commands"]
|
||||||
|
|
||||||
|
module2 := ctx.ModuleForTests("commonapex", "android_common_commonapex")
|
||||||
|
apexRule2 := module2.Rule("apexRule")
|
||||||
|
copyCmds2 := apexRule2.Args["copy_commands"]
|
||||||
|
|
||||||
|
ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_core_shared_myapex")
|
||||||
|
ensureListContains(t, ctx.ModuleVariantsForTests("libcommon"), "android_arm64_armv8-a_core_shared_commonapex")
|
||||||
|
ensureContains(t, copyCmds1, "image.apex/lib64/mylib.so")
|
||||||
|
ensureContains(t, copyCmds2, "image.apex/lib64/libcommon.so")
|
||||||
|
ensureNotContains(t, copyCmds1, "image.apex/lib64/libcommon.so")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApexUsesFailsIfNotProvided(t *testing.T) {
|
||||||
|
testApexError(t, `uses: "commonapex" does not provide native_shared_libs`, `
|
||||||
|
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 TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
run := func() int {
|
run := func() int {
|
||||||
setUp()
|
setUp()
|
||||||
|
Reference in New Issue
Block a user