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:
Jooyung Han
2019-06-27 11:30:33 +09:00
parent cfec40c41b
commit 5c998b9ff8
2 changed files with 215 additions and 5 deletions

View File

@@ -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.

View File

@@ -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()