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:
@@ -199,6 +199,13 @@ func LastUniqueStrings(list []string) []string {
|
|||||||
return list[totalSkip:]
|
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
|
// checkCalledFromInit panics if a Go package's init function is not on the
|
||||||
// call stack.
|
// call stack.
|
||||||
func checkCalledFromInit() {
|
func checkCalledFromInit() {
|
||||||
|
54
apex/apex.go
54
apex/apex.go
@@ -46,6 +46,14 @@ var (
|
|||||||
Description: "fs_config ${out}",
|
Description: "fs_config ${out}",
|
||||||
}, "ro_paths", "exec_paths")
|
}, "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
|
// TODO(b/113233103): make sure that file_contexts is sane, i.e., validate
|
||||||
// against the binary policy using sefcontext_compiler -p <policy>.
|
// against the binary policy using sefcontext_compiler -p <policy>.
|
||||||
|
|
||||||
@@ -139,6 +147,7 @@ func init() {
|
|||||||
pctx.HostBinToolVariable("soong_zip", "soong_zip")
|
pctx.HostBinToolVariable("soong_zip", "soong_zip")
|
||||||
pctx.HostBinToolVariable("zip2zip", "zip2zip")
|
pctx.HostBinToolVariable("zip2zip", "zip2zip")
|
||||||
pctx.HostBinToolVariable("zipalign", "zipalign")
|
pctx.HostBinToolVariable("zipalign", "zipalign")
|
||||||
|
pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
|
||||||
|
|
||||||
android.RegisterModuleType("apex", apexBundleFactory)
|
android.RegisterModuleType("apex", apexBundleFactory)
|
||||||
android.RegisterModuleType("apex_test", testApexBundleFactory)
|
android.RegisterModuleType("apex_test", testApexBundleFactory)
|
||||||
@@ -427,6 +436,9 @@ type apexBundle struct {
|
|||||||
flattened bool
|
flattened bool
|
||||||
|
|
||||||
testApex bool
|
testApex bool
|
||||||
|
|
||||||
|
// intermediate path for apex_manifest.json
|
||||||
|
manifestOut android.WritablePath
|
||||||
}
|
}
|
||||||
|
|
||||||
func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
|
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)
|
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
|
// Check if "uses" requirements are met with dependent apexBundles
|
||||||
var providedNativeSharedLibs []string
|
var providedNativeSharedLibs []string
|
||||||
useVendor := proptools.Bool(a.properties.Use_vendor)
|
useVendor := proptools.Bool(a.properties.Use_vendor)
|
||||||
@@ -783,6 +799,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
switch depTag {
|
switch depTag {
|
||||||
case sharedLibTag:
|
case sharedLibTag:
|
||||||
if cc, ok := child.(*cc.Module); ok {
|
if cc, ok := child.(*cc.Module); ok {
|
||||||
|
if cc.HasStubsVariants() {
|
||||||
|
provideNativeLibs = append(provideNativeLibs, cc.OutputFile().Path().Base())
|
||||||
|
}
|
||||||
fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, handleSpecialLibs)
|
fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, handleSpecialLibs)
|
||||||
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeSharedLib, cc, nil})
|
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeSharedLib, cc, nil})
|
||||||
return true
|
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) {
|
if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.externalDeps) {
|
||||||
a.externalDeps = append(a.externalDeps, cc.Name())
|
a.externalDeps = append(a.externalDeps, cc.Name())
|
||||||
}
|
}
|
||||||
|
requireNativeLibs = append(requireNativeLibs, cc.OutputFile().Path().Base())
|
||||||
// Don't track further
|
// Don't track further
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -954,6 +974,21 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
a.installDir = android.PathForModuleInstall(ctx, "apex")
|
a.installDir = android.PathForModuleInstall(ctx, "apex")
|
||||||
a.filesInfo = filesInfo
|
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() {
|
if a.apexTypes.zip() {
|
||||||
a.buildUnflattenedApex(ctx, zipApex)
|
a.buildUnflattenedApex(ctx, zipApex)
|
||||||
}
|
}
|
||||||
@@ -1001,8 +1036,6 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap
|
|||||||
a.container_private_key_file = key
|
a.container_private_key_file = key
|
||||||
}
|
}
|
||||||
|
|
||||||
manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
|
|
||||||
|
|
||||||
var abis []string
|
var abis []string
|
||||||
for _, target := range ctx.MultiTargets() {
|
for _, target := range ctx.MultiTargets() {
|
||||||
if len(target.Arch.Abi) > 0 {
|
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(android.Paths(nil), filesToCopy...)
|
||||||
implicitInputs = append(implicitInputs, manifest)
|
implicitInputs = append(implicitInputs, a.manifestOut)
|
||||||
|
|
||||||
outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String()
|
outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String()
|
||||||
prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
|
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,
|
"tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
|
||||||
"image_dir": android.PathForModuleOut(ctx, "image"+suffix).String(),
|
"image_dir": android.PathForModuleOut(ctx, "image"+suffix).String(),
|
||||||
"copy_commands": strings.Join(copyCommands, " && "),
|
"copy_commands": strings.Join(copyCommands, " && "),
|
||||||
"manifest": manifest.String(),
|
"manifest": a.manifestOut.String(),
|
||||||
"file_contexts": fileContexts.String(),
|
"file_contexts": fileContexts.String(),
|
||||||
"canned_fs_config": cannedFsConfig.String(),
|
"canned_fs_config": cannedFsConfig.String(),
|
||||||
"key": a.private_key_file.String(),
|
"key": a.private_key_file.String(),
|
||||||
@@ -1165,7 +1198,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap
|
|||||||
"tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
|
"tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
|
||||||
"image_dir": android.PathForModuleOut(ctx, "image"+suffix).String(),
|
"image_dir": android.PathForModuleOut(ctx, "image"+suffix).String(),
|
||||||
"copy_commands": strings.Join(copyCommands, " && "),
|
"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() {
|
if a.installable() {
|
||||||
// For flattened APEX, do nothing but make sure that apex_manifest.json and apex_pubkey are also copied along
|
// For flattened APEX, do nothing but make sure that apex_manifest.json and apex_pubkey are also copied along
|
||||||
// with other ordinary files.
|
// with other ordinary files.
|
||||||
manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
|
a.filesInfo = append(a.filesInfo, apexFile{a.manifestOut, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
|
||||||
|
|
||||||
// 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})
|
|
||||||
|
|
||||||
// rename to apex_pubkey
|
// rename to apex_pubkey
|
||||||
copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey")
|
copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey")
|
||||||
|
@@ -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
|
// Minimal test
|
||||||
func TestBasicApex(t *testing.T) {
|
func TestBasicApex(t *testing.T) {
|
||||||
ctx, _ := testApex(t, `
|
ctx, _ := testApex(t, `
|
||||||
@@ -1060,6 +1067,109 @@ func TestHeaderLibsDependency(t *testing.T) {
|
|||||||
ensureContains(t, cFlags, "-Imy_include")
|
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) {
|
func TestNonTestApex(t *testing.T) {
|
||||||
ctx, _ := testApex(t, `
|
ctx, _ := testApex(t, `
|
||||||
apex {
|
apex {
|
||||||
|
Reference in New Issue
Block a user