Put dependency in apex_manifest.json

To generate ld.config.txt dynamically(b/123722631), each APEX should
provide some dependency information:
a) list of libraries which other APEXes(or system) can use from this apex
b) list of libraries which this apex uses from other APEXes(or system)

This change puts dependency information in apex_manifest.json at
build-time with two additional keys:
a) provideNativeLibs
b) requireNativeLibs

Bug: 138695532
Test: m (runs soong tests)
Test: find $OUT/apex -name apex_manifest.json  -exec cat {} \;
 (shows contents of apex_manifest.json files)

Change-Id: Iaad12c8c35454222ad177ce923cce76ef12a8a5a
This commit is contained in:
Jooyung Han
2019-08-01 17:41:43 +09:00
parent 395ab52ee9
commit e16330393a
3 changed files with 156 additions and 15 deletions

View File

@@ -199,6 +199,13 @@ func LastUniqueStrings(list []string) []string {
return list[totalSkip:]
}
// SortedUniqueStrings returns what the name says
func SortedUniqueStrings(list []string) []string {
unique := FirstUniqueStrings(list)
sort.Strings(unique)
return unique
}
// checkCalledFromInit panics if a Go package's init function is not on the
// call stack.
func checkCalledFromInit() {

View File

@@ -46,6 +46,14 @@ var (
Description: "fs_config ${out}",
}, "ro_paths", "exec_paths")
injectApexDependency = pctx.StaticRule("injectApexDependency", blueprint.RuleParams{
Command: `rm -f $out && ${jsonmodify} $in ` +
`-a provideNativeLibs ${provideNativeLibs} ` +
`-a requireNativeLibs ${requireNativeLibs} -o $out`,
CommandDeps: []string{"${jsonmodify}"},
Description: "Inject dependency into ${out}",
}, "provideNativeLibs", "requireNativeLibs")
// TODO(b/113233103): make sure that file_contexts is sane, i.e., validate
// against the binary policy using sefcontext_compiler -p <policy>.
@@ -139,6 +147,7 @@ func init() {
pctx.HostBinToolVariable("soong_zip", "soong_zip")
pctx.HostBinToolVariable("zip2zip", "zip2zip")
pctx.HostBinToolVariable("zipalign", "zipalign")
pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
android.RegisterModuleType("apex", apexBundleFactory)
android.RegisterModuleType("apex_test", testApexBundleFactory)
@@ -427,6 +436,9 @@ type apexBundle struct {
flattened bool
testApex bool
// intermediate path for apex_manifest.json
manifestOut android.WritablePath
}
func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
@@ -751,6 +763,10 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
// native lib dependencies
var provideNativeLibs []string
var requireNativeLibs []string
// Check if "uses" requirements are met with dependent apexBundles
var providedNativeSharedLibs []string
useVendor := proptools.Bool(a.properties.Use_vendor)
@@ -783,6 +799,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
switch depTag {
case sharedLibTag:
if cc, ok := child.(*cc.Module); ok {
if cc.HasStubsVariants() {
provideNativeLibs = append(provideNativeLibs, cc.OutputFile().Path().Base())
}
fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, handleSpecialLibs)
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeSharedLib, cc, nil})
return true
@@ -894,6 +913,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.externalDeps) {
a.externalDeps = append(a.externalDeps, cc.Name())
}
requireNativeLibs = append(requireNativeLibs, cc.OutputFile().Path().Base())
// Don't track further
return false
}
@@ -954,6 +974,21 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.installDir = android.PathForModuleInstall(ctx, "apex")
a.filesInfo = filesInfo
a.manifestOut = android.PathForModuleOut(ctx, "apex_manifest.json")
// put dependency({provide|require}NativeLibs) in apex_manifest.json
manifestSrc := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
provideNativeLibs = android.SortedUniqueStrings(provideNativeLibs)
requireNativeLibs = android.SortedUniqueStrings(android.RemoveListFromList(requireNativeLibs, provideNativeLibs))
ctx.Build(pctx, android.BuildParams{
Rule: injectApexDependency,
Input: manifestSrc,
Output: a.manifestOut,
Args: map[string]string{
"provideNativeLibs": strings.Join(provideNativeLibs, " "),
"requireNativeLibs": strings.Join(requireNativeLibs, " "),
},
})
if a.apexTypes.zip() {
a.buildUnflattenedApex(ctx, zipApex)
}
@@ -1001,8 +1036,6 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap
a.container_private_key_file = key
}
manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
var abis []string
for _, target := range ctx.MultiTargets() {
if len(target.Arch.Abi) > 0 {
@@ -1032,7 +1065,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap
}
}
implicitInputs := append(android.Paths(nil), filesToCopy...)
implicitInputs = append(implicitInputs, manifest)
implicitInputs = append(implicitInputs, a.manifestOut)
outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String()
prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
@@ -1127,7 +1160,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap
"tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
"image_dir": android.PathForModuleOut(ctx, "image"+suffix).String(),
"copy_commands": strings.Join(copyCommands, " && "),
"manifest": manifest.String(),
"manifest": a.manifestOut.String(),
"file_contexts": fileContexts.String(),
"canned_fs_config": cannedFsConfig.String(),
"key": a.private_key_file.String(),
@@ -1165,7 +1198,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap
"tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
"image_dir": android.PathForModuleOut(ctx, "image"+suffix).String(),
"copy_commands": strings.Join(copyCommands, " && "),
"manifest": manifest.String(),
"manifest": a.manifestOut.String(),
},
})
}
@@ -1196,16 +1229,7 @@ func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) {
if a.installable() {
// For flattened APEX, do nothing but make sure that apex_manifest.json and apex_pubkey are also copied along
// with other ordinary files.
manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
// rename to apex_manifest.json
copiedManifest := android.PathForModuleOut(ctx, "apex_manifest.json")
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
Input: manifest,
Output: copiedManifest,
})
a.filesInfo = append(a.filesInfo, apexFile{copiedManifest, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
a.filesInfo = append(a.filesInfo, apexFile{a.manifestOut, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
// rename to apex_pubkey
copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey")

View File

@@ -270,6 +270,13 @@ func ensureListNotContains(t *testing.T, result []string, notExpected string) {
}
}
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, _ := testApex(t, `
@@ -1060,6 +1067,109 @@ func TestHeaderLibsDependency(t *testing.T) {
ensureContains(t, cFlags, "-Imy_include")
}
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",
}
apex {
name: "myapex_dep",
key: "myapex.key",
native_shared_libs: ["lib_dep"],
compile_multilib: "both",
file_contexts: "myapex",
}
apex {
name: "myapex_provider",
key: "myapex.key",
native_shared_libs: ["libfoo"],
compile_multilib: "both",
file_contexts: "myapex",
}
apex {
name: "myapex_selfcontained",
key: "myapex.key",
native_shared_libs: ["lib_dep", "libfoo"],
compile_multilib: "both",
file_contexts: "myapex",
}
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",
}
cc_library {
name: "lib_dep",
srcs: ["mylib.cpp"],
shared_libs: ["libfoo"],
system_shared_libs: [],
stl: "none",
}
cc_library {
name: "libfoo",
srcs: ["mytest.cpp"],
stubs: {
versions: ["1"],
},
system_shared_libs: [],
stl: "none",
}
`)
names := func(s string) (ns []string) {
for _, n := range strings.Split(s, " ") {
if len(n) > 0 {
ns = append(ns, n)
}
}
return
}
var injectRule android.TestingBuildParams
var provideNativeLibs, requireNativeLibs []string
injectRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep").Rule("injectApexDependency")
provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
ensureListEmpty(t, provideNativeLibs)
ensureListEmpty(t, requireNativeLibs)
injectRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep").Rule("injectApexDependency")
provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
ensureListEmpty(t, provideNativeLibs)
ensureListContains(t, requireNativeLibs, "libfoo.so")
injectRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider").Rule("injectApexDependency")
provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
ensureListContains(t, provideNativeLibs, "libfoo.so")
ensureListEmpty(t, requireNativeLibs)
injectRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained").Rule("injectApexDependency")
provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
ensureListContains(t, provideNativeLibs, "libfoo.so")
ensureListEmpty(t, requireNativeLibs)
}
func TestNonTestApex(t *testing.T) {
ctx, _ := testApex(t, `
apex {