Loading android/module.go +43 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ import ( "os" "path" "path/filepath" "regexp" "strings" "text/scanner" Loading Loading @@ -135,6 +136,13 @@ type BaseModuleContext interface { // GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1] GetTagPath() []blueprint.DependencyTag // GetPathString is supposed to be called in visit function passed in WalkDeps() // and returns a multi-line string showing the modules and dependency tags // among them along the top-down dependency path from a start module to current child module. // skipFirst when set to true, the output doesn't include the start module, // which is already printed when this function is used along with ModuleErrorf(). GetPathString(skipFirst bool) string AddMissingDependencies(missingDeps []string) Target() Target Loading Loading @@ -1734,6 +1742,41 @@ func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag { return b.tagPath } // A regexp for removing boilerplate from BaseDependencyTag from the string representation of // a dependency tag. var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:blueprint.BaseDependencyTag{}\E(, )?`) // PrettyPrintTag returns string representation of the tag, but prefers // custom String() method if available. func PrettyPrintTag(tag blueprint.DependencyTag) string { // Use tag's custom String() method if available. if stringer, ok := tag.(fmt.Stringer); ok { return stringer.String() } // Otherwise, get a default string representation of the tag's struct. tagString := fmt.Sprintf("%#v", tag) // Remove the boilerplate from BaseDependencyTag as it adds no value. tagString = tagCleaner.ReplaceAllString(tagString, "") return tagString } func (b *baseModuleContext) GetPathString(skipFirst bool) string { sb := strings.Builder{} tagPath := b.GetTagPath() walkPath := b.GetWalkPath() if !skipFirst { sb.WriteString(walkPath[0].String()) } for i, m := range walkPath[1:] { sb.WriteString("\n") sb.WriteString(fmt.Sprintf(" via tag %s\n", PrettyPrintTag(tagPath[i]))) sb.WriteString(fmt.Sprintf(" -> %s", m.String())) } return sb.String() } func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) { m.bp.VisitAllModuleVariants(func(module blueprint.Module) { visit(module.(Module)) Loading apex/apex.go +41 −28 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ import ( "fmt" "path" "path/filepath" "regexp" "sort" "strings" "sync" Loading Loading @@ -1811,24 +1810,6 @@ func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) int { return intVer } // A regexp for removing boilerplate from BaseDependencyTag from the string representation of // a dependency tag. var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:blueprint.BaseDependencyTag{}\E(, )?`) func PrettyPrintTag(tag blueprint.DependencyTag) string { // Use tag's custom String() method if available. if stringer, ok := tag.(fmt.Stringer); ok { return stringer.String() } // Otherwise, get a default string representation of the tag's struct. tagString := fmt.Sprintf("%#v", tag) // Remove the boilerplate from BaseDependencyTag as it adds no value. tagString = tagCleaner.ReplaceAllString(tagString, "") return tagString } // Ensures that the dependencies are marked as available for this APEX func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { // Let's be practical. Availability for test, host, and the VNDK apex isn't important Loading Loading @@ -1863,14 +1844,7 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { if to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) { return true } message := "" tagPath := ctx.GetTagPath() // Skip the first module as that will be added at the start of the error message by ctx.ModuleErrorf(). walkPath := ctx.GetWalkPath()[1:] for i, m := range walkPath { message = fmt.Sprintf("%s\n via tag %s\n -> %s", message, PrettyPrintTag(tagPath[i]), m.String()) } ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, message) ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, ctx.GetPathString(true)) // Visit this module's dependencies to check and report any issues with their availability. return true }) Loading @@ -1886,6 +1860,44 @@ func (a *apexBundle) checkUpdatable(ctx android.ModuleContext) { } } // Ensures that a lib providing stub isn't statically linked func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext) { // Practically, we only care about regular APEXes on the device. if ctx.Host() || a.testApex || a.vndkApex { return } a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { if ccm, ok := to.(*cc.Module); ok { apexName := ctx.ModuleName() fromName := ctx.OtherModuleName(from) toName := ctx.OtherModuleName(to) // If `to` is not actually in the same APEX as `from` then it does not need apex_available and neither // do any of its dependencies. if am, ok := from.(android.DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) { // As soon as the dependency graph crosses the APEX boundary, don't go further. return false } // The dynamic linker and crash_dump tool in the runtime APEX is the only exception to this rule. // It can't make the static dependencies dynamic because it can't // do the dynamic linking for itself. if apexName == "com.android.runtime" && (fromName == "linker" || fromName == "crash_dump") { return false } isStubLibraryFromOtherApex := ccm.HasStubsVariants() && !android.DirectlyInApex(apexName, toName) if isStubLibraryFromOtherApex && !externalDep { ctx.ModuleErrorf("%q required by %q is a native library providing stub. "+ "It shouldn't be included in this APEX via static linking. Dependency path: %s", to.String(), fromName, ctx.GetPathString(false)) } } return true }) } func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild() switch a.properties.ApexType { Loading Loading @@ -1923,6 +1935,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.checkApexAvailability(ctx) a.checkUpdatable(ctx) a.checkStaticLinkingToStubLibraries(ctx) handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case) Loading Loading @@ -2134,7 +2147,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName)) } } else if am.CanHaveApexVariants() && am.IsInstallableToApex() { ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", PrettyPrintTag(depTag), depName) ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName) } } } Loading apex/apex_test.go +36 −0 Original line number Diff line number Diff line Loading @@ -4774,6 +4774,42 @@ func TestTestFor(t *testing.T) { ensureNotContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared_1/mylib.so") } func TestNoStaticLinkingToStubsLib(t *testing.T) { testApexError(t, `.*required by "mylib" is a native library providing stub.*`, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library { name: "mylib", srcs: ["mylib.cpp"], static_libs: ["otherlib"], system_shared_libs: [], stl: "none", apex_available: [ "myapex" ], } cc_library { name: "otherlib", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", stubs: { versions: ["1", "2", "3"], }, apex_available: [ "myapex" ], } `) } func TestMain(m *testing.M) { run := func() int { setUp() Loading cc/cc.go +3 −0 Original line number Diff line number Diff line Loading @@ -2862,6 +2862,9 @@ func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu return false } } } else if ctx.OtherModuleDependencyTag(dep) == llndkImplDep { // We don't track beyond LLNDK return false } return true } Loading Loading
android/module.go +43 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ import ( "os" "path" "path/filepath" "regexp" "strings" "text/scanner" Loading Loading @@ -135,6 +136,13 @@ type BaseModuleContext interface { // GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1] GetTagPath() []blueprint.DependencyTag // GetPathString is supposed to be called in visit function passed in WalkDeps() // and returns a multi-line string showing the modules and dependency tags // among them along the top-down dependency path from a start module to current child module. // skipFirst when set to true, the output doesn't include the start module, // which is already printed when this function is used along with ModuleErrorf(). GetPathString(skipFirst bool) string AddMissingDependencies(missingDeps []string) Target() Target Loading Loading @@ -1734,6 +1742,41 @@ func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag { return b.tagPath } // A regexp for removing boilerplate from BaseDependencyTag from the string representation of // a dependency tag. var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:blueprint.BaseDependencyTag{}\E(, )?`) // PrettyPrintTag returns string representation of the tag, but prefers // custom String() method if available. func PrettyPrintTag(tag blueprint.DependencyTag) string { // Use tag's custom String() method if available. if stringer, ok := tag.(fmt.Stringer); ok { return stringer.String() } // Otherwise, get a default string representation of the tag's struct. tagString := fmt.Sprintf("%#v", tag) // Remove the boilerplate from BaseDependencyTag as it adds no value. tagString = tagCleaner.ReplaceAllString(tagString, "") return tagString } func (b *baseModuleContext) GetPathString(skipFirst bool) string { sb := strings.Builder{} tagPath := b.GetTagPath() walkPath := b.GetWalkPath() if !skipFirst { sb.WriteString(walkPath[0].String()) } for i, m := range walkPath[1:] { sb.WriteString("\n") sb.WriteString(fmt.Sprintf(" via tag %s\n", PrettyPrintTag(tagPath[i]))) sb.WriteString(fmt.Sprintf(" -> %s", m.String())) } return sb.String() } func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) { m.bp.VisitAllModuleVariants(func(module blueprint.Module) { visit(module.(Module)) Loading
apex/apex.go +41 −28 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ import ( "fmt" "path" "path/filepath" "regexp" "sort" "strings" "sync" Loading Loading @@ -1811,24 +1810,6 @@ func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) int { return intVer } // A regexp for removing boilerplate from BaseDependencyTag from the string representation of // a dependency tag. var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:blueprint.BaseDependencyTag{}\E(, )?`) func PrettyPrintTag(tag blueprint.DependencyTag) string { // Use tag's custom String() method if available. if stringer, ok := tag.(fmt.Stringer); ok { return stringer.String() } // Otherwise, get a default string representation of the tag's struct. tagString := fmt.Sprintf("%#v", tag) // Remove the boilerplate from BaseDependencyTag as it adds no value. tagString = tagCleaner.ReplaceAllString(tagString, "") return tagString } // Ensures that the dependencies are marked as available for this APEX func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { // Let's be practical. Availability for test, host, and the VNDK apex isn't important Loading Loading @@ -1863,14 +1844,7 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { if to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) { return true } message := "" tagPath := ctx.GetTagPath() // Skip the first module as that will be added at the start of the error message by ctx.ModuleErrorf(). walkPath := ctx.GetWalkPath()[1:] for i, m := range walkPath { message = fmt.Sprintf("%s\n via tag %s\n -> %s", message, PrettyPrintTag(tagPath[i]), m.String()) } ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, message) ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, ctx.GetPathString(true)) // Visit this module's dependencies to check and report any issues with their availability. return true }) Loading @@ -1886,6 +1860,44 @@ func (a *apexBundle) checkUpdatable(ctx android.ModuleContext) { } } // Ensures that a lib providing stub isn't statically linked func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext) { // Practically, we only care about regular APEXes on the device. if ctx.Host() || a.testApex || a.vndkApex { return } a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { if ccm, ok := to.(*cc.Module); ok { apexName := ctx.ModuleName() fromName := ctx.OtherModuleName(from) toName := ctx.OtherModuleName(to) // If `to` is not actually in the same APEX as `from` then it does not need apex_available and neither // do any of its dependencies. if am, ok := from.(android.DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) { // As soon as the dependency graph crosses the APEX boundary, don't go further. return false } // The dynamic linker and crash_dump tool in the runtime APEX is the only exception to this rule. // It can't make the static dependencies dynamic because it can't // do the dynamic linking for itself. if apexName == "com.android.runtime" && (fromName == "linker" || fromName == "crash_dump") { return false } isStubLibraryFromOtherApex := ccm.HasStubsVariants() && !android.DirectlyInApex(apexName, toName) if isStubLibraryFromOtherApex && !externalDep { ctx.ModuleErrorf("%q required by %q is a native library providing stub. "+ "It shouldn't be included in this APEX via static linking. Dependency path: %s", to.String(), fromName, ctx.GetPathString(false)) } } return true }) } func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild() switch a.properties.ApexType { Loading Loading @@ -1923,6 +1935,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.checkApexAvailability(ctx) a.checkUpdatable(ctx) a.checkStaticLinkingToStubLibraries(ctx) handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case) Loading Loading @@ -2134,7 +2147,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName)) } } else if am.CanHaveApexVariants() && am.IsInstallableToApex() { ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", PrettyPrintTag(depTag), depName) ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName) } } } Loading
apex/apex_test.go +36 −0 Original line number Diff line number Diff line Loading @@ -4774,6 +4774,42 @@ func TestTestFor(t *testing.T) { ensureNotContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared_1/mylib.so") } func TestNoStaticLinkingToStubsLib(t *testing.T) { testApexError(t, `.*required by "mylib" is a native library providing stub.*`, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } cc_library { name: "mylib", srcs: ["mylib.cpp"], static_libs: ["otherlib"], system_shared_libs: [], stl: "none", apex_available: [ "myapex" ], } cc_library { name: "otherlib", srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", stubs: { versions: ["1", "2", "3"], }, apex_available: [ "myapex" ], } `) } func TestMain(m *testing.M) { run := func() int { setUp() Loading
cc/cc.go +3 −0 Original line number Diff line number Diff line Loading @@ -2862,6 +2862,9 @@ func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu return false } } } else if ctx.OtherModuleDependencyTag(dep) == llndkImplDep { // We don't track beyond LLNDK return false } return true } Loading