<apex_name>-deps-info correctly tracks dependencies

The APEX dependency is more correctly tracked. Previously, the
dependency was tracked while we gather modules that will be installed to
an APEX. This actually was incorrect because we skipped many dependency
types that we don't need to follow to gather the modules list, such as
the headers dependency.

Now, the dependency is tracked directly when a module is mutated for an
APEX. In other words, if a module is mutated for an apex X, then the
module will appear in the X-deps-into.txt file.

This change also changes the format of the txt file. It now clearly
shows why a module is included in the APEX by showing the list of
modules that depend on the module.

Bug: 146323213
Test: m
Change-Id: I0a70cf9cce56e36565f9d55683fdaace8748a081
This commit is contained in:
Jiyong Park 2020-02-07 17:25:49 +09:00
parent 201cedd608
commit 678c881a4f
6 changed files with 60 additions and 64 deletions

View File

@ -1466,6 +1466,12 @@ func (af *apexFile) AvailableToPlatform() bool {
return false return false
} }
type depInfo struct {
to string
from []string
isExternal bool
}
type apexBundle struct { type apexBundle struct {
android.ModuleBase android.ModuleBase
android.DefaultableModuleBase android.DefaultableModuleBase
@ -1499,10 +1505,8 @@ type apexBundle struct {
// list of module names that should be installed along with this APEX // list of module names that should be installed along with this APEX
requiredDeps []string 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) // list of module names that this APEX is including (to be shown via *-deps-info target)
internalDeps []string depInfos map[string]depInfo
testApex bool testApex bool
vndkApex bool vndkApex bool
@ -1983,6 +1987,31 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
}) })
} }
// Collects the list of module names that directly or indirectly contributes to the payload of this APEX
func (a *apexBundle) collectDepsInfo(ctx android.ModuleContext) {
a.depInfos = make(map[string]depInfo)
a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
if from.Name() == to.Name() {
// This can happen for cc.reuseObjTag. We are not interested in tracking this.
return
}
if info, exists := a.depInfos[to.Name()]; exists {
if !android.InList(from.Name(), info.from) {
info.from = append(info.from, from.Name())
}
info.isExternal = info.isExternal && externalDep
a.depInfos[to.Name()] = info
} else {
a.depInfos[to.Name()] = depInfo{
to: to.Name(),
from: []string{from.Name()},
isExternal: externalDep,
}
}
})
}
func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild() buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild()
switch a.properties.ApexType { switch a.properties.ApexType {
@ -2020,6 +2049,8 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.checkApexAvailability(ctx) a.checkApexAvailability(ctx)
a.collectDepsInfo(ctx)
handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case) handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
// native lib dependencies // native lib dependencies
@ -2051,13 +2082,11 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}) })
var filesInfo []apexFile var filesInfo []apexFile
// TODO(jiyong) do this using walkPayloadDeps
ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool { ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
depTag := ctx.OtherModuleDependencyTag(child) depTag := ctx.OtherModuleDependencyTag(child)
depName := ctx.OtherModuleName(child) depName := ctx.OtherModuleName(child)
if _, isDirectDep := parent.(*apexBundle); isDirectDep { if _, isDirectDep := parent.(*apexBundle); isDirectDep {
if depTag != keyTag && depTag != certificateTag {
a.internalDeps = append(a.internalDeps, depName)
}
switch depTag { switch depTag {
case sharedLibTag: case sharedLibTag:
if c, ok := child.(*cc.Module); ok { if c, ok := child.(*cc.Module); ok {
@ -2194,7 +2223,6 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.requiredDeps) { if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.requiredDeps) {
a.requiredDeps = append(a.requiredDeps, cc.Name()) a.requiredDeps = append(a.requiredDeps, cc.Name())
} }
a.externalDeps = append(a.externalDeps, depName)
requireNativeLibs = append(requireNativeLibs, cc.OutputFile().Path().Base()) requireNativeLibs = append(requireNativeLibs, cc.OutputFile().Path().Base())
// Don't track further // Don't track further
return false return false
@ -2202,8 +2230,6 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs) af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs)
af.transitiveDep = true af.transitiveDep = true
filesInfo = append(filesInfo, af) filesInfo = append(filesInfo, af)
a.internalDeps = append(a.internalDeps, depName)
a.internalDeps = append(a.internalDeps, cc.AllStaticDeps()...)
return true // track transitive dependencies return true // track transitive dependencies
} }
} else if cc.IsTestPerSrcDepTag(depTag) { } else if cc.IsTestPerSrcDepTag(depTag) {
@ -2220,10 +2246,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
return true // track transitive dependencies return true // track transitive dependencies
} }
} else if java.IsJniDepTag(depTag) { } else if java.IsJniDepTag(depTag) {
a.externalDeps = append(a.externalDeps, depName)
return true return true
} else if java.IsStaticLibDepTag(depTag) {
a.internalDeps = append(a.internalDeps, depName)
} else if am.CanHaveApexVariants() && am.IsInstallableToApex() { } else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName) ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName)
} }

View File

@ -549,10 +549,11 @@ func TestBasicApex(t *testing.T) {
ensureListContains(t, noticeInputs, "custom_notice") ensureListContains(t, noticeInputs, "custom_notice")
depsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("myapex-deps-info.txt").Args["content"], "\\n") 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, "myjar <- myapex")
ensureListContains(t, depsInfo, "internal mylib") ensureListContains(t, depsInfo, "mylib <- myapex")
ensureListContains(t, depsInfo, "internal mylib2") ensureListContains(t, depsInfo, "mylib2 <- mylib")
ensureListContains(t, depsInfo, "internal myotherjar") ensureListContains(t, depsInfo, "myotherjar <- myjar")
ensureListContains(t, depsInfo, "mysharedjar (external) <- myjar")
} }
func TestDefaults(t *testing.T) { func TestDefaults(t *testing.T) {
@ -796,6 +797,7 @@ func TestApexWithExplicitStubsDependency(t *testing.T) {
name: "mylib", name: "mylib",
srcs: ["mylib.cpp"], srcs: ["mylib.cpp"],
shared_libs: ["libfoo#10"], shared_libs: ["libfoo#10"],
static_libs: ["libbaz"],
system_shared_libs: [], system_shared_libs: [],
stl: "none", stl: "none",
apex_available: [ "myapex2" ], apex_available: [ "myapex2" ],
@ -819,6 +821,14 @@ func TestApexWithExplicitStubsDependency(t *testing.T) {
stl: "none", stl: "none",
} }
cc_library_static {
name: "libbaz",
srcs: ["mylib.cpp"],
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex2" ],
}
`) `)
apexRule := ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Rule("apexRule") apexRule := ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Rule("apexRule")
@ -846,10 +856,10 @@ func TestApexWithExplicitStubsDependency(t *testing.T) {
ensureNotContains(t, libFooStubsLdFlags, "libbar.so") ensureNotContains(t, libFooStubsLdFlags, "libbar.so")
depsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("myapex2-deps-info.txt").Args["content"], "\\n") 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") ensureListContains(t, depsInfo, "mylib <- myapex2")
ensureListNotContains(t, depsInfo, "internal libfoo") ensureListContains(t, depsInfo, "libbaz <- mylib")
ensureListNotContains(t, depsInfo, "external mylib") ensureListContains(t, depsInfo, "libfoo (external) <- mylib")
} }
func TestApexWithRuntimeLibsDependency(t *testing.T) { func TestApexWithRuntimeLibsDependency(t *testing.T) {

View File

@ -596,19 +596,14 @@ func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) {
return return
} }
internalDeps := a.internalDeps
externalDeps := a.externalDeps
internalDeps = android.SortedUniqueStrings(internalDeps)
externalDeps = android.SortedUniqueStrings(externalDeps)
externalDeps = android.RemoveListFromList(externalDeps, internalDeps)
var content strings.Builder var content strings.Builder
for _, name := range internalDeps { for _, key := range android.SortedStringKeys(a.depInfos) {
fmt.Fprintf(&content, "internal %s\\n", name) info := a.depInfos[key]
} toName := info.to
for _, name := range externalDeps { if info.isExternal {
fmt.Fprintf(&content, "external %s\\n", name) toName = toName + " (external)"
}
fmt.Fprintf(&content, "%s <- %s\\n", toName, strings.Join(android.SortedUniqueStrings(info.from), ", "))
} }
depsInfoFile := android.PathForOutput(ctx, a.Name()+"-deps-info.txt") depsInfoFile := android.PathForOutput(ctx, a.Name()+"-deps-info.txt")

View File

@ -403,13 +403,6 @@ func IsSharedDepTag(depTag blueprint.DependencyTag) bool {
return ok && ccDepTag.Shared 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 { func IsRuntimeDepTag(depTag blueprint.DependencyTag) bool {
ccDepTag, ok := depTag.(DependencyTag) ccDepTag, ok := depTag.(DependencyTag)
return ok && ccDepTag == runtimeDepTag return ok && ccDepTag == runtimeDepTag
@ -475,9 +468,6 @@ type Module struct {
makeLinkType string makeLinkType string
// Kythe (source file indexer) paths for this compilation module // Kythe (source file indexer) paths for this compilation module
kytheFiles android.Paths 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 { func (c *Module) Toc() android.OptionalPath {
@ -1288,15 +1278,6 @@ func orderStaticModuleDeps(module LinkableInterface, staticDeps []LinkableInterf
return results 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 { func (c *Module) IsTestPerSrcAllTestsVariation() bool {
test, ok := c.linker.(testPerSrc) test, ok := c.linker.(testPerSrc)
return ok && test.isAllTestsVariation() return ok && test.isAllTestsVariation()
@ -2378,8 +2359,6 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
c.sabi.Properties.ReexportedIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludes) c.sabi.Properties.ReexportedIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludes)
} }
c.allStaticDeps = gatherTransitiveStaticDeps(directStaticDeps)
return depPaths return depPaths
} }
@ -2539,10 +2518,6 @@ func (c *Module) installable() bool {
return false return false
} }
func (c *Module) AllStaticDeps() []string {
return c.allStaticDeps
}
func (c *Module) AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) { func (c *Module) AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
if c.linker != nil { if c.linker != nil {
if library, ok := c.linker.(*libraryDecorator); ok { if library, ok := c.linker.(*libraryDecorator); ok {

View File

@ -54,8 +54,6 @@ type LinkableInterface interface {
ToolchainLibrary() bool ToolchainLibrary() bool
NdkPrebuiltStl() bool NdkPrebuiltStl() bool
StubDecorator() bool StubDecorator() bool
AllStaticDeps() []string
} }
type DependencyTag struct { type DependencyTag struct {

View File

@ -354,11 +354,6 @@ func (mod *Module) GetStaticVariant() cc.LinkableInterface {
return nil return nil
} }
func (mod *Module) AllStaticDeps() []string {
// TODO(jiyong): do this for rust?
return nil
}
func (mod *Module) Module() android.Module { func (mod *Module) Module() android.Module {
return mod return mod
} }