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"}
|
||||
keyTag = dependencyTag{name: "key"}
|
||||
certificateTag = dependencyTag{name: "certificate"}
|
||||
usesTag = dependencyTag{name: "uses"}
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -147,6 +148,7 @@ func init() {
|
||||
android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
||||
ctx.TopDown("apex_deps", apexDepsMutator)
|
||||
ctx.BottomUp("apex", apexMutator).Parallel()
|
||||
ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -187,6 +189,11 @@ func apexMutator(mctx android.BottomUpMutatorContext) {
|
||||
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 {
|
||||
// List of native libraries
|
||||
@@ -272,6 +279,12 @@ type apexBundleProperties struct {
|
||||
|
||||
// List of sanitizer names that this APEX is enabled for
|
||||
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 {
|
||||
@@ -727,6 +740,30 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
|
||||
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 {
|
||||
if _, ok := parent.(*apexBundle); ok {
|
||||
// direct dependencies
|
||||
@@ -815,6 +852,11 @@ 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 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 the dependency is a stubs lib, don't include it in this APEX,
|
||||
// but make sure that the lib is installed on the device.
|
||||
|
@@ -29,7 +29,32 @@ import (
|
||||
|
||||
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 {
|
||||
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.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
|
||||
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.TopDown("apex_deps", apexDepsMutator)
|
||||
ctx.BottomUp("apex", apexMutator)
|
||||
ctx.BottomUp("apex_uses", apexUsesMutator)
|
||||
ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).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_keytest-file_contexts": nil,
|
||||
"system/sepolicy/apex/otherapex-file_contexts": nil,
|
||||
"system/sepolicy/apex/commonapex-file_contexts": nil,
|
||||
"mylib.cpp": nil,
|
||||
"mytest.cpp": nil,
|
||||
"mylib_common.cpp": nil,
|
||||
"myprebuilt": nil,
|
||||
"my_include": 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,
|
||||
"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() {
|
||||
@@ -210,6 +234,7 @@ func tearDown() {
|
||||
|
||||
// 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)
|
||||
}
|
||||
@@ -217,18 +242,21 @@ func ensureContains(t *testing.T, result string, expected string) {
|
||||
|
||||
// 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 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)
|
||||
}
|
||||
@@ -789,6 +817,30 @@ func TestUseVendor(t *testing.T) {
|
||||
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) {
|
||||
ctx := testApex(t, `
|
||||
apex {
|
||||
@@ -1321,6 +1373,122 @@ func TestApexWithTests(t *testing.T) {
|
||||
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) {
|
||||
run := func() int {
|
||||
setUp()
|
||||
|
Reference in New Issue
Block a user