From 114ff53f5e66f4493dcee443db677c09e0b9b32b Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 16 Dec 2019 23:42:46 +0900 Subject: [PATCH] m -deps-info prints the internal/external deps of the APEX We need to have a way to see the list of modules that directly or indirectly contribute to an APEX. People find it difficult to determine whether a module is included in which APEXes because APEX tracks indirect dependencies as well as direct dependencies. Therefore, just looking at Android.bp for the APEX itself doesn't give the answer. This change adds a new make target -deps-info, which generates out/soong/-deps-info.txt file that shows the internal and external dependencies of the said APEX. Here, internal means the dependencies are actually part of the APEX, while external means the dependencies are still external to the APEX. Bug: 146323213 Test: m (apex_test amended) Change-Id: I33d1ccf5d1ca335d71cd6ced0f5f66b8c3886d13 --- apex/androidmk.go | 4 ++-- apex/apex.go | 24 +++++++++++++++++++----- apex/apex_test.go | 25 +++++++++++++++++++------ apex/builder.go | 37 +++++++++++++++++++++++++++++++++++++ cc/cc.go | 25 +++++++++++++++++++++++++ cc/linkable.go | 2 ++ java/java.go | 8 ++++++++ rust/rust.go | 5 +++++ 8 files changed, 117 insertions(+), 13 deletions(-) diff --git a/apex/androidmk.go b/apex/androidmk.go index c42b3484e..3462c7e44 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -185,8 +185,8 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { if len(moduleNames) > 0 { fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(moduleNames, " ")) } - if len(a.externalDeps) > 0 { - fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(a.externalDeps, " ")) + if len(a.requiredDeps) > 0 { + fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(a.requiredDeps, " ")) } var postInstallCommands []string if a.prebuiltFileToDelete != "" { diff --git a/apex/apex.go b/apex/apex.go index b27b54e3e..aadc2c12c 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -511,8 +511,13 @@ type apexBundle struct { // list of files to be included in this apex filesInfo []apexFile - // list of module names that this APEX is depending on + // list of module names that should be installed along with this APEX + requiredDeps []string + + // list of module names that this APEX is depending on (to be shown via *-deps-info target) externalDeps []string + // list of module names that this APEX is including (to be shown via *-deps-info target) + internalDeps []string testApex bool vndkApex bool @@ -925,7 +930,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.primaryApexType = true if ctx.Config().InstallExtraFlattenedApexes() { - a.externalDeps = append(a.externalDeps, a.Name()+flattenedSuffix) + a.requiredDeps = append(a.requiredDeps, a.Name()+flattenedSuffix) } } case zipApex: @@ -984,6 +989,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { depTag := ctx.OtherModuleDependencyTag(child) depName := ctx.OtherModuleName(child) if _, isDirectDep := parent.(*apexBundle); isDirectDep { + if depTag != keyTag && depTag != certificateTag { + a.internalDeps = append(a.internalDeps, depName) + } switch depTag { case sharedLibTag: if cc, ok := child.(*cc.Module); ok { @@ -1114,9 +1122,10 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { // // Always include if we are a host-apex however since those won't have any // system libraries. - if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.externalDeps) { - a.externalDeps = append(a.externalDeps, cc.Name()) + if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.requiredDeps) { + a.requiredDeps = append(a.requiredDeps, cc.Name()) } + a.externalDeps = append(a.externalDeps, depName) requireNativeLibs = append(requireNativeLibs, cc.OutputFile().Path().Base()) // Don't track further return false @@ -1124,6 +1133,8 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs) af.transitiveDep = true filesInfo = append(filesInfo, af) + a.internalDeps = append(a.internalDeps, depName) + a.internalDeps = append(a.internalDeps, cc.AllStaticDeps()...) return true // track transitive dependencies } } else if cc.IsTestPerSrcDepTag(depTag) { @@ -1139,8 +1150,10 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { return true // track transitive dependencies } } else if java.IsJniDepTag(depTag) { - // Do nothing for JNI dep. JNI libraries are always embedded in APK-in-APEX. + a.externalDeps = append(a.externalDeps, depName) return true + } else if java.IsStaticLibDepTag(depTag) { + a.internalDeps = append(a.internalDeps, depName) } else if am.CanHaveApexVariants() && am.IsInstallableToApex() { ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName) } @@ -1238,6 +1251,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { apexName := proptools.StringDefault(a.properties.Apex_name, a.Name()) a.compatSymlinks = makeCompatSymlinks(apexName, ctx) + a.buildApexDependencyInfo(ctx) } func newApexBundle() *apexBundle { diff --git a/apex/apex_test.go b/apex/apex_test.go index 0d929ed2a..9e9f88262 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -219,6 +219,7 @@ func testApexContext(t *testing.T, bp string, handlers ...testCustomizer) (*andr "apex_manifest.json": nil, "AndroidManifest.xml": nil, "system/sepolicy/apex/myapex-file_contexts": nil, + "system/sepolicy/apex/myapex2-file_contexts": nil, "system/sepolicy/apex/otherapex-file_contexts": nil, "system/sepolicy/apex/commonapex-file_contexts": nil, "system/sepolicy/apex/com.android.vndk-file_contexts": nil, @@ -520,6 +521,12 @@ func TestBasicApex(t *testing.T) { } ensureListContains(t, noticeInputs, "NOTICE") ensureListContains(t, noticeInputs, "custom_notice") + + depsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("myapex-deps-info.txt").Args["content"], "\\n") + ensureListContains(t, depsInfo, "internal myjar") + ensureListContains(t, depsInfo, "internal mylib") + ensureListContains(t, depsInfo, "internal mylib2") + ensureListContains(t, depsInfo, "internal myotherjar") } func TestDefaults(t *testing.T) { @@ -740,13 +747,13 @@ func TestApexWithStubs(t *testing.T) { func TestApexWithExplicitStubsDependency(t *testing.T) { ctx, _ := testApex(t, ` apex { - name: "myapex", - key: "myapex.key", + name: "myapex2", + key: "myapex2.key", native_shared_libs: ["mylib"], } apex_key { - name: "myapex.key", + name: "myapex2.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } @@ -779,7 +786,7 @@ func TestApexWithExplicitStubsDependency(t *testing.T) { `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + apexRule := ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included @@ -791,7 +798,7 @@ func TestApexWithExplicitStubsDependency(t *testing.T) { // Ensure that dependency of stubs is not included ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"] + mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex2").Rule("ld").Args["libFlags"] // Ensure that mylib is linking with version 10 of libfoo ensureContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared_10/libfoo.so") @@ -802,6 +809,12 @@ func TestApexWithExplicitStubsDependency(t *testing.T) { // Ensure that libfoo stubs is not linking to libbar (since it is a stubs) ensureNotContains(t, libFooStubsLdFlags, "libbar.so") + + depsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("myapex2-deps-info.txt").Args["content"], "\\n") + ensureListContains(t, depsInfo, "internal mylib") + ensureListContains(t, depsInfo, "external libfoo") + ensureListNotContains(t, depsInfo, "internal libfoo") + ensureListNotContains(t, depsInfo, "external mylib") } func TestApexWithRuntimeLibsDependency(t *testing.T) { @@ -2652,7 +2665,7 @@ func TestInstallExtraFlattenedApexes(t *testing.T) { config.TestProductVariables.InstallExtraFlattenedApexes = proptools.BoolPtr(true) }) ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) - ensureListContains(t, ab.externalDeps, "myapex.flattened") + ensureListContains(t, ab.requiredDeps, "myapex.flattened") mk := android.AndroidMkDataForTest(t, config, "", ab) var builder strings.Builder mk.Custom(&builder, ab.Name(), "TARGET_", "", mk) diff --git a/apex/builder.go b/apex/builder.go index fe465f57b..5bc21d611 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -553,3 +553,40 @@ func (a *apexBundle) getOverrideManifestPackageName(ctx android.ModuleContext) s } return "" } + +func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) { + if !a.primaryApexType { + return + } + + internalDeps := a.internalDeps + externalDeps := a.externalDeps + + internalDeps = android.SortedUniqueStrings(internalDeps) + externalDeps = android.SortedUniqueStrings(externalDeps) + externalDeps = android.RemoveListFromList(externalDeps, internalDeps) + + var content strings.Builder + for _, name := range internalDeps { + fmt.Fprintf(&content, "internal %s\\n", name) + } + for _, name := range externalDeps { + fmt.Fprintf(&content, "external %s\\n", name) + } + + depsInfoFile := android.PathForOutput(ctx, a.Name()+"-deps-info.txt") + ctx.Build(pctx, android.BuildParams{ + Rule: android.WriteFile, + Description: "Dependency Info", + Output: depsInfoFile, + Args: map[string]string{ + "content": content.String(), + }, + }) + + ctx.Build(pctx, android.BuildParams{ + Rule: android.Phony, + Output: android.PathForPhony(ctx, a.Name()+"-deps-info"), + Inputs: []android.Path{depsInfoFile}, + }) +} diff --git a/cc/cc.go b/cc/cc.go index 0c3222536..0bab41fd0 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -398,6 +398,13 @@ func IsSharedDepTag(depTag blueprint.DependencyTag) bool { return ok && ccDepTag.Shared } +func IsStaticDepTag(depTag blueprint.DependencyTag) bool { + ccDepTag, ok := depTag.(DependencyTag) + return ok && (ccDepTag == staticExportDepTag || + ccDepTag == lateStaticDepTag || + ccDepTag == wholeStaticDepTag) +} + func IsRuntimeDepTag(depTag blueprint.DependencyTag) bool { ccDepTag, ok := depTag.(DependencyTag) return ok && ccDepTag == runtimeDepTag @@ -463,6 +470,9 @@ type Module struct { makeLinkType string // Kythe (source file indexer) paths for this compilation module kytheFiles android.Paths + + // name of the modules that are direct or indirect static deps of this module + allStaticDeps []string } func (c *Module) Toc() android.OptionalPath { @@ -1258,6 +1268,15 @@ func orderStaticModuleDeps(module LinkableInterface, staticDeps []LinkableInterf return results } +func gatherTransitiveStaticDeps(staticDeps []LinkableInterface) []string { + var ret []string + for _, dep := range staticDeps { + ret = append(ret, dep.Module().Name()) + ret = append(ret, dep.AllStaticDeps()...) + } + return android.FirstUniqueStrings(ret) +} + func (c *Module) IsTestPerSrcAllTestsVariation() bool { test, ok := c.linker.(testPerSrc) return ok && test.isAllTestsVariation() @@ -2328,6 +2347,8 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { c.sabi.Properties.ReexportedIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludes) } + c.allStaticDeps = gatherTransitiveStaticDeps(directStaticDeps) + return depPaths } @@ -2463,6 +2484,10 @@ func (c *Module) installable() bool { return c.installer != nil && !c.Properties.PreventInstall && c.IsForPlatform() && c.outputFile.Valid() } +func (c *Module) AllStaticDeps() []string { + return c.allStaticDeps +} + func (c *Module) AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) { if c.linker != nil { if library, ok := c.linker.(*libraryDecorator); ok { diff --git a/cc/linkable.go b/cc/linkable.go index 815d405c8..106092b2c 100644 --- a/cc/linkable.go +++ b/cc/linkable.go @@ -51,6 +51,8 @@ type LinkableInterface interface { ToolchainLibrary() bool NdkPrebuiltStl() bool StubDecorator() bool + + AllStaticDeps() []string } type DependencyTag struct { diff --git a/java/java.go b/java/java.go index 27f69b848..9f26e1907 100644 --- a/java/java.go +++ b/java/java.go @@ -492,6 +492,14 @@ var ( usesLibTag = dependencyTag{name: "uses-library"} ) +func IsLibDepTag(depTag blueprint.DependencyTag) bool { + return depTag == libTag +} + +func IsStaticLibDepTag(depTag blueprint.DependencyTag) bool { + return depTag == staticLibTag +} + type sdkDep struct { useModule, useFiles, useDefaultLibs, invalidVersion bool diff --git a/rust/rust.go b/rust/rust.go index 0eab8d222..14513fbf9 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -346,6 +346,11 @@ func (mod *Module) GetStaticVariant() cc.LinkableInterface { return nil } +func (mod *Module) AllStaticDeps() []string { + // TODO(jiyong): do this for rust? + return nil +} + func (mod *Module) Module() android.Module { return mod }