Refactor apexBundle code.
Move dependency walker out of GenerateAndroidBuildActions, reduce IDE
warnings.
Test: treehugger
Change-Id: I520c59772b1da7102d2a2364b2c56789455ea7fb
diff --git a/apex/apex.go b/apex/apex.go
index 7e913e8..5678b06 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1338,7 +1338,7 @@
var _ android.DepIsInSameApex = (*apexBundle)(nil)
// Implements android.DepInInSameApex
-func (a *apexBundle) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+func (a *apexBundle) DepIsInSameApex(_ android.BaseModuleContext, _ android.Module) bool {
// direct deps of an APEX bundle are all part of the APEX bundle
// TODO(jiyong): shouldn't we look into the payload field of the dependencyTag?
return true
@@ -1474,7 +1474,7 @@
}
// Then follow the global setting
- globalSanitizerNames := []string{}
+ var globalSanitizerNames []string
if a.Host() {
globalSanitizerNames = config.SanitizeHost()
} else {
@@ -1790,6 +1790,382 @@
}
}
+type visitorContext struct {
+ // all the files that will be included in this APEX
+ filesInfo []apexFile
+
+ // native lib dependencies
+ provideNativeLibs []string
+ requireNativeLibs []string
+
+ handleSpecialLibs bool
+}
+
+func (vctx *visitorContext) normalizeFileInfo() {
+ encountered := make(map[string]apexFile)
+ for _, f := range vctx.filesInfo {
+ dest := filepath.Join(f.installDir, f.builtFile.Base())
+ if e, ok := encountered[dest]; !ok {
+ encountered[dest] = f
+ } else {
+ // If a module is directly included and also transitively depended on
+ // consider it as directly included.
+ e.transitiveDep = e.transitiveDep && f.transitiveDep
+ encountered[dest] = e
+ }
+ }
+ vctx.filesInfo = vctx.filesInfo[:0]
+ for _, v := range encountered {
+ vctx.filesInfo = append(vctx.filesInfo, v)
+ }
+ sort.Slice(vctx.filesInfo, func(i, j int) bool {
+ // Sort by destination path so as to ensure consistent ordering even if the source of the files
+ // changes.
+ return vctx.filesInfo[i].path() < vctx.filesInfo[j].path()
+ })
+}
+
+func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, child, parent blueprint.Module) bool {
+ depTag := ctx.OtherModuleDependencyTag(child)
+ if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
+ return false
+ }
+ if mod, ok := child.(android.Module); ok && !mod.Enabled() {
+ return false
+ }
+ depName := ctx.OtherModuleName(child)
+ if _, isDirectDep := parent.(*apexBundle); isDirectDep {
+ switch depTag {
+ case sharedLibTag, jniLibTag:
+ isJniLib := depTag == jniLibTag
+ switch ch := child.(type) {
+ case *cc.Module:
+ fi := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
+ fi.isJniLib = isJniLib
+ vctx.filesInfo = append(vctx.filesInfo, fi)
+ // Collect the list of stub-providing libs except:
+ // - VNDK libs are only for vendors
+ // - bootstrap bionic libs are treated as provided by system
+ if ch.HasStubsVariants() && !a.vndkApex && !cc.InstallToBootstrap(ch.BaseModuleName(), ctx.Config()) {
+ vctx.provideNativeLibs = append(vctx.provideNativeLibs, fi.stem())
+ }
+ return true // track transitive dependencies
+ case *rust.Module:
+ fi := apexFileForRustLibrary(ctx, ch)
+ fi.isJniLib = isJniLib
+ vctx.filesInfo = append(vctx.filesInfo, fi)
+ return true // track transitive dependencies
+ default:
+ propertyName := "native_shared_libs"
+ if isJniLib {
+ propertyName = "jni_libs"
+ }
+ ctx.PropertyErrorf(propertyName, "%q is not a cc_library or cc_library_shared module", depName)
+ }
+ case executableTag:
+ switch ch := child.(type) {
+ case *cc.Module:
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForExecutable(ctx, ch))
+ return true // track transitive dependencies
+ case *python.Module:
+ if ch.HostToolPath().Valid() {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForPyBinary(ctx, ch))
+ }
+ case bootstrap.GoBinaryTool:
+ if a.Host() {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForGoBinary(ctx, depName, ch))
+ }
+ case *rust.Module:
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForRustExecutable(ctx, ch))
+ return true // track transitive dependencies
+ default:
+ ctx.PropertyErrorf("binaries",
+ "%q is neither cc_binary, rust_binary, (embedded) py_binary, (host) blueprint_go_binary, nor (host) bootstrap_go_binary", depName)
+ }
+ case shBinaryTag:
+ if csh, ok := child.(*sh.ShBinary); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForShBinary(ctx, csh))
+ } else {
+ ctx.PropertyErrorf("sh_binaries", "%q is not a sh_binary module", depName)
+ }
+ case bcpfTag:
+ bcpfModule, ok := child.(*java.BootclasspathFragmentModule)
+ if !ok {
+ ctx.PropertyErrorf("bootclasspath_fragments", "%q is not a bootclasspath_fragment module", depName)
+ return false
+ }
+
+ vctx.filesInfo = append(vctx.filesInfo, apexBootclasspathFragmentFiles(ctx, child)...)
+ for _, makeModuleName := range bcpfModule.BootImageDeviceInstallMakeModules() {
+ a.requiredDeps = append(a.requiredDeps, makeModuleName)
+ }
+ return true
+ case sscpfTag:
+ if _, ok := child.(*java.SystemServerClasspathModule); !ok {
+ ctx.PropertyErrorf("systemserverclasspath_fragments",
+ "%q is not a systemserverclasspath_fragment module", depName)
+ return false
+ }
+ if af := apexClasspathFragmentProtoFile(ctx, child); af != nil {
+ vctx.filesInfo = append(vctx.filesInfo, *af)
+ }
+ return true
+ case javaLibTag:
+ switch child.(type) {
+ case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport, *java.Import:
+ af := apexFileForJavaModule(ctx, child.(javaModule))
+ if !af.ok() {
+ ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
+ return false
+ }
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ default:
+ ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
+ }
+ case androidAppTag:
+ switch ap := child.(type) {
+ case *java.AndroidApp:
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForAndroidApp(ctx, ap))
+ return true // track transitive dependencies
+ case *java.AndroidAppImport:
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForAndroidApp(ctx, ap))
+ case *java.AndroidTestHelperApp:
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForAndroidApp(ctx, ap))
+ case *java.AndroidAppSet:
+ appDir := "app"
+ if ap.Privileged() {
+ appDir = "priv-app"
+ }
+ // TODO(b/224589412, b/226559955): Ensure that the dirname is
+ // suffixed so that PackageManager correctly invalidates the
+ // existing installed apk in favour of the new APK-in-APEX.
+ // See bugs for more information.
+ appDirName := filepath.Join(appDir, ap.BaseModuleName()+"@"+sanitizedBuildIdForPath(ctx))
+ af := newApexFile(ctx, ap.OutputFile(), ap.BaseModuleName(), appDirName, appSet, ap)
+ af.certificate = java.PresignedCertificate
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ default:
+ ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
+ }
+ case rroTag:
+ if rro, ok := child.(java.RuntimeResourceOverlayModule); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForRuntimeResourceOverlay(ctx, rro))
+ } else {
+ ctx.PropertyErrorf("rros", "%q is not an runtime_resource_overlay module", depName)
+ }
+ case bpfTag:
+ if bpfProgram, ok := child.(bpf.BpfModule); ok {
+ filesToCopy, _ := bpfProgram.OutputFiles("")
+ apex_sub_dir := bpfProgram.SubDir()
+ for _, bpfFile := range filesToCopy {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForBpfProgram(ctx, bpfFile, apex_sub_dir, bpfProgram))
+ }
+ } else {
+ ctx.PropertyErrorf("bpfs", "%q is not a bpf module", depName)
+ }
+ case fsTag:
+ if fs, ok := child.(filesystem.Filesystem); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForFilesystem(ctx, fs.OutputPath(), fs))
+ } else {
+ ctx.PropertyErrorf("filesystems", "%q is not a filesystem module", depName)
+ }
+ case prebuiltTag:
+ if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+ } else {
+ ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
+ }
+ case compatConfigTag:
+ if compatConfig, ok := child.(java.PlatformCompatConfigIntf); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForCompatConfig(ctx, compatConfig, depName))
+ } else {
+ ctx.PropertyErrorf("compat_configs", "%q is not a platform_compat_config module", depName)
+ }
+ case testTag:
+ if ccTest, ok := child.(*cc.Module); ok {
+ if ccTest.IsTestPerSrcAllTestsVariation() {
+ // Multiple-output test module (where `test_per_src: true`).
+ //
+ // `ccTest` is the "" ("all tests") variation of a `test_per_src` module.
+ // We do not add this variation to `filesInfo`, as it has no output;
+ // however, we do add the other variations of this module as indirect
+ // dependencies (see below).
+ } else {
+ // Single-output test module (where `test_per_src: false`).
+ af := apexFileForExecutable(ctx, ccTest)
+ af.class = nativeTest
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ }
+ return true // track transitive dependencies
+ } else {
+ ctx.PropertyErrorf("tests", "%q is not a cc module", depName)
+ }
+ case keyTag:
+ if key, ok := child.(*apexKey); ok {
+ a.privateKeyFile = key.privateKeyFile
+ a.publicKeyFile = key.publicKeyFile
+ } else {
+ ctx.PropertyErrorf("key", "%q is not an apex_key module", depName)
+ }
+ case certificateTag:
+ if dep, ok := child.(*java.AndroidAppCertificate); ok {
+ a.containerCertificateFile = dep.Certificate.Pem
+ a.containerPrivateKeyFile = dep.Certificate.Key
+ } else {
+ ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", depName)
+ }
+ case android.PrebuiltDepTag:
+ // If the prebuilt is force disabled, remember to delete the prebuilt file
+ // that might have been installed in the previous builds
+ if prebuilt, ok := child.(prebuilt); ok && prebuilt.isForceDisabled() {
+ a.prebuiltFileToDelete = prebuilt.InstallFilename()
+ }
+ }
+ return false
+ }
+
+ if a.vndkApex {
+ return false
+ }
+
+ // indirect dependencies
+ am, ok := child.(android.ApexModule)
+ if !ok {
+ return false
+ }
+ // We cannot use a switch statement on `depTag` here as the checked
+ // tags used below are private (e.g. `cc.sharedDepTag`).
+ if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) {
+ if ch, ok := child.(*cc.Module); ok {
+ if ch.UseVndk() && proptools.Bool(a.properties.Use_vndk_as_stable) && ch.IsVndk() {
+ vctx.requireNativeLibs = append(vctx.requireNativeLibs, ":vndk")
+ return false
+ }
+ af := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
+ af.transitiveDep = true
+
+ // Always track transitive dependencies for host.
+ if a.Host() {
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true
+ }
+
+ abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo)
+ if !abInfo.Contents.DirectlyInApex(depName) && (ch.IsStubs() || ch.HasStubsVariants()) {
+ // If the dependency is a stubs lib, don't include it in this APEX,
+ // but make sure that the lib is installed on the device.
+ // In case no APEX is having the lib, the lib is installed to the system
+ // partition.
+ //
+ // Always include if we are a host-apex however since those won't have any
+ // system libraries.
+ if !am.DirectlyInAnyApex() {
+ // we need a module name for Make
+ name := ch.ImplementationModuleNameForMake(ctx) + ch.Properties.SubName
+ if !android.InList(name, a.requiredDeps) {
+ a.requiredDeps = append(a.requiredDeps, name)
+ }
+ }
+ vctx.requireNativeLibs = append(vctx.requireNativeLibs, af.stem())
+ // Don't track further
+ return false
+ }
+
+ // If the dep is not considered to be in the same
+ // apex, don't add it to filesInfo so that it is not
+ // included in this APEX.
+ // TODO(jiyong): move this to at the top of the
+ // else-if clause for the indirect dependencies.
+ // Currently, that's impossible because we would
+ // like to record requiredNativeLibs even when
+ // DepIsInSameAPex is false. We also shouldn't do
+ // this for host.
+ //
+ // TODO(jiyong): explain why the same module is passed in twice.
+ // Switching the first am to parent breaks lots of tests.
+ if !android.IsDepInSameApex(ctx, am, am) {
+ return false
+ }
+
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ } else if rm, ok := child.(*rust.Module); ok {
+ af := apexFileForRustLibrary(ctx, rm)
+ af.transitiveDep = true
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ }
+ } else if cc.IsTestPerSrcDepTag(depTag) {
+ if ch, ok := child.(*cc.Module); ok {
+ af := apexFileForExecutable(ctx, ch)
+ // Handle modules created as `test_per_src` variations of a single test module:
+ // use the name of the generated test binary (`fileToCopy`) instead of the name
+ // of the original test module (`depName`, shared by all `test_per_src`
+ // variations of that module).
+ af.androidMkModuleName = filepath.Base(af.builtFile.String())
+ // these are not considered transitive dep
+ af.transitiveDep = false
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ }
+ } else if cc.IsHeaderDepTag(depTag) {
+ // nothing
+ } else if java.IsJniDepTag(depTag) {
+ // Because APK-in-APEX embeds jni_libs transitively, we don't need to track transitive deps
+ } else if java.IsXmlPermissionsFileDepTag(depTag) {
+ if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+ }
+ } else if rust.IsDylibDepTag(depTag) {
+ if rustm, ok := child.(*rust.Module); ok && rustm.IsInstallableToApex() {
+ af := apexFileForRustLibrary(ctx, rustm)
+ af.transitiveDep = true
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ }
+ } else if rust.IsRlibDepTag(depTag) {
+ // Rlib is statically linked, but it might have shared lib
+ // dependencies. Track them.
+ return true
+ } else if java.IsBootclasspathFragmentContentDepTag(depTag) {
+ // Add the contents of the bootclasspath fragment to the apex.
+ switch child.(type) {
+ case *java.Library, *java.SdkLibrary:
+ javaModule := child.(javaModule)
+ af := apexFileForBootclasspathFragmentContentModule(ctx, parent, javaModule)
+ if !af.ok() {
+ ctx.PropertyErrorf("bootclasspath_fragments",
+ "bootclasspath_fragment content %q is not configured to be compiled into dex", depName)
+ return false
+ }
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ default:
+ ctx.PropertyErrorf("bootclasspath_fragments",
+ "bootclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
+ }
+ } else if java.IsSystemServerClasspathFragmentContentDepTag(depTag) {
+ // Add the contents of the systemserverclasspath fragment to the apex.
+ switch child.(type) {
+ case *java.Library, *java.SdkLibrary:
+ af := apexFileForJavaModule(ctx, child.(javaModule))
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ default:
+ ctx.PropertyErrorf("systemserverclasspath_fragments",
+ "systemserverclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
+ }
+ } else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok {
+ // nothing
+ } else if depTag == android.DarwinUniversalVariantTag {
+ // nothing
+ } else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
+ ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
+ }
+ return false
+}
+
// Creates build rules for an APEX. It consists of the following major steps:
//
// 1) do some validity checks such as apex_available, min_sdk_version, etc.
@@ -1812,386 +2188,23 @@
////////////////////////////////////////////////////////////////////////////////////////////
// 2) traverse the dependency tree to collect apexFile structs from them.
- // all the files that will be included in this APEX
- var filesInfo []apexFile
-
- // native lib dependencies
- var provideNativeLibs []string
- var requireNativeLibs []string
-
- handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
-
// Collect the module directory for IDE info in java/jdeps.go.
a.modulePaths = append(a.modulePaths, ctx.ModuleDir())
// TODO(jiyong): do this using WalkPayloadDeps
// TODO(jiyong): make this clean!!!
- ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
- depTag := ctx.OtherModuleDependencyTag(child)
- if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
- return false
- }
- if mod, ok := child.(android.Module); ok && !mod.Enabled() {
- return false
- }
- depName := ctx.OtherModuleName(child)
- if _, isDirectDep := parent.(*apexBundle); isDirectDep {
- switch depTag {
- case sharedLibTag, jniLibTag:
- isJniLib := depTag == jniLibTag
- if c, ok := child.(*cc.Module); ok {
- fi := apexFileForNativeLibrary(ctx, c, handleSpecialLibs)
- fi.isJniLib = isJniLib
- filesInfo = append(filesInfo, fi)
- // Collect the list of stub-providing libs except:
- // - VNDK libs are only for vendors
- // - bootstrap bionic libs are treated as provided by system
- if c.HasStubsVariants() && !a.vndkApex && !cc.InstallToBootstrap(c.BaseModuleName(), ctx.Config()) {
- provideNativeLibs = append(provideNativeLibs, fi.stem())
- }
- return true // track transitive dependencies
- } else if r, ok := child.(*rust.Module); ok {
- fi := apexFileForRustLibrary(ctx, r)
- fi.isJniLib = isJniLib
- filesInfo = append(filesInfo, fi)
- return true // track transitive dependencies
- } else {
- propertyName := "native_shared_libs"
- if isJniLib {
- propertyName = "jni_libs"
- }
- ctx.PropertyErrorf(propertyName, "%q is not a cc_library or cc_library_shared module", depName)
- }
- case executableTag:
- if cc, ok := child.(*cc.Module); ok {
- filesInfo = append(filesInfo, apexFileForExecutable(ctx, cc))
- return true // track transitive dependencies
- } else if py, ok := child.(*python.Module); ok && py.HostToolPath().Valid() {
- filesInfo = append(filesInfo, apexFileForPyBinary(ctx, py))
- } else if gb, ok := child.(bootstrap.GoBinaryTool); ok && a.Host() {
- filesInfo = append(filesInfo, apexFileForGoBinary(ctx, depName, gb))
- } else if rust, ok := child.(*rust.Module); ok {
- filesInfo = append(filesInfo, apexFileForRustExecutable(ctx, rust))
- return true // track transitive dependencies
- } else {
- ctx.PropertyErrorf("binaries", "%q is neither cc_binary, rust_binary, (embedded) py_binary, (host) blueprint_go_binary, nor (host) bootstrap_go_binary", depName)
- }
- case shBinaryTag:
- if sh, ok := child.(*sh.ShBinary); ok {
- filesInfo = append(filesInfo, apexFileForShBinary(ctx, sh))
- } else {
- ctx.PropertyErrorf("sh_binaries", "%q is not a sh_binary module", depName)
- }
- case bcpfTag:
- {
- bcpfModule, ok := child.(*java.BootclasspathFragmentModule)
- if !ok {
- ctx.PropertyErrorf("bootclasspath_fragments", "%q is not a bootclasspath_fragment module", depName)
- return false
- }
-
- filesToAdd := apexBootclasspathFragmentFiles(ctx, child)
- filesInfo = append(filesInfo, filesToAdd...)
- for _, makeModuleName := range bcpfModule.BootImageDeviceInstallMakeModules() {
- a.requiredDeps = append(a.requiredDeps, makeModuleName)
- }
- return true
- }
- case sscpfTag:
- {
- if _, ok := child.(*java.SystemServerClasspathModule); !ok {
- ctx.PropertyErrorf("systemserverclasspath_fragments", "%q is not a systemserverclasspath_fragment module", depName)
- return false
- }
- if af := apexClasspathFragmentProtoFile(ctx, child); af != nil {
- filesInfo = append(filesInfo, *af)
- }
- return true
- }
- case javaLibTag:
- switch child.(type) {
- case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport, *java.Import:
- af := apexFileForJavaModule(ctx, child.(javaModule))
- if !af.ok() {
- ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
- return false
- }
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- default:
- ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
- }
- case androidAppTag:
- if ap, ok := child.(*java.AndroidApp); ok {
- filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
- return true // track transitive dependencies
- } else if ap, ok := child.(*java.AndroidAppImport); ok {
- filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
- } else if ap, ok := child.(*java.AndroidTestHelperApp); ok {
- filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
- } else if ap, ok := child.(*java.AndroidAppSet); ok {
- appDir := "app"
- if ap.Privileged() {
- appDir = "priv-app"
- }
- // TODO(b/224589412, b/226559955): Ensure that the dirname is
- // suffixed so that PackageManager correctly invalidates the
- // existing installed apk in favour of the new APK-in-APEX.
- // See bugs for more information.
- appDirName := filepath.Join(appDir, ap.BaseModuleName()+"@"+sanitizedBuildIdForPath(ctx))
- af := newApexFile(ctx, ap.OutputFile(), ap.BaseModuleName(), appDirName, appSet, ap)
- af.certificate = java.PresignedCertificate
- filesInfo = append(filesInfo, af)
- } else {
- ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
- }
- case rroTag:
- if rro, ok := child.(java.RuntimeResourceOverlayModule); ok {
- filesInfo = append(filesInfo, apexFileForRuntimeResourceOverlay(ctx, rro))
- } else {
- ctx.PropertyErrorf("rros", "%q is not an runtime_resource_overlay module", depName)
- }
- case bpfTag:
- if bpfProgram, ok := child.(bpf.BpfModule); ok {
- filesToCopy, _ := bpfProgram.OutputFiles("")
- apex_sub_dir := bpfProgram.SubDir()
- for _, bpfFile := range filesToCopy {
- filesInfo = append(filesInfo, apexFileForBpfProgram(ctx, bpfFile, apex_sub_dir, bpfProgram))
- }
- } else {
- ctx.PropertyErrorf("bpfs", "%q is not a bpf module", depName)
- }
- case fsTag:
- if fs, ok := child.(filesystem.Filesystem); ok {
- filesInfo = append(filesInfo, apexFileForFilesystem(ctx, fs.OutputPath(), fs))
- } else {
- ctx.PropertyErrorf("filesystems", "%q is not a filesystem module", depName)
- }
- case prebuiltTag:
- if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
- filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
- } else {
- ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
- }
- case compatConfigTag:
- if compatConfig, ok := child.(java.PlatformCompatConfigIntf); ok {
- filesInfo = append(filesInfo, apexFileForCompatConfig(ctx, compatConfig, depName))
- } else {
- ctx.PropertyErrorf("compat_configs", "%q is not a platform_compat_config module", depName)
- }
- case testTag:
- if ccTest, ok := child.(*cc.Module); ok {
- if ccTest.IsTestPerSrcAllTestsVariation() {
- // Multiple-output test module (where `test_per_src: true`).
- //
- // `ccTest` is the "" ("all tests") variation of a `test_per_src` module.
- // We do not add this variation to `filesInfo`, as it has no output;
- // however, we do add the other variations of this module as indirect
- // dependencies (see below).
- } else {
- // Single-output test module (where `test_per_src: false`).
- af := apexFileForExecutable(ctx, ccTest)
- af.class = nativeTest
- filesInfo = append(filesInfo, af)
- }
- return true // track transitive dependencies
- } else {
- ctx.PropertyErrorf("tests", "%q is not a cc module", depName)
- }
- case keyTag:
- if key, ok := child.(*apexKey); ok {
- a.privateKeyFile = key.privateKeyFile
- a.publicKeyFile = key.publicKeyFile
- } else {
- ctx.PropertyErrorf("key", "%q is not an apex_key module", depName)
- }
- return false
- case certificateTag:
- if dep, ok := child.(*java.AndroidAppCertificate); ok {
- a.containerCertificateFile = dep.Certificate.Pem
- a.containerPrivateKeyFile = dep.Certificate.Key
- } else {
- ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", depName)
- }
- case android.PrebuiltDepTag:
- // If the prebuilt is force disabled, remember to delete the prebuilt file
- // that might have been installed in the previous builds
- if prebuilt, ok := child.(prebuilt); ok && prebuilt.isForceDisabled() {
- a.prebuiltFileToDelete = prebuilt.InstallFilename()
- }
- }
- } else if !a.vndkApex {
- // indirect dependencies
- if am, ok := child.(android.ApexModule); ok {
- // We cannot use a switch statement on `depTag` here as the checked
- // tags used below are private (e.g. `cc.sharedDepTag`).
- if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) {
- if cc, ok := child.(*cc.Module); ok {
- if cc.UseVndk() && proptools.Bool(a.properties.Use_vndk_as_stable) && cc.IsVndk() {
- requireNativeLibs = append(requireNativeLibs, ":vndk")
- return false
- }
- af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs)
- af.transitiveDep = true
-
- // Always track transitive dependencies for host.
- if a.Host() {
- filesInfo = append(filesInfo, af)
- return true
- }
-
- abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo)
- if !abInfo.Contents.DirectlyInApex(depName) && (cc.IsStubs() || cc.HasStubsVariants()) {
- // If the dependency is a stubs lib, don't include it in this APEX,
- // but make sure that the lib is installed on the device.
- // In case no APEX is having the lib, the lib is installed to the system
- // partition.
- //
- // Always include if we are a host-apex however since those won't have any
- // system libraries.
- if !am.DirectlyInAnyApex() {
- // we need a module name for Make
- name := cc.ImplementationModuleNameForMake(ctx) + cc.Properties.SubName
- if !android.InList(name, a.requiredDeps) {
- a.requiredDeps = append(a.requiredDeps, name)
- }
- }
- requireNativeLibs = append(requireNativeLibs, af.stem())
- // Don't track further
- return false
- }
-
- // If the dep is not considered to be in the same
- // apex, don't add it to filesInfo so that it is not
- // included in this APEX.
- // TODO(jiyong): move this to at the top of the
- // else-if clause for the indirect dependencies.
- // Currently, that's impossible because we would
- // like to record requiredNativeLibs even when
- // DepIsInSameAPex is false. We also shouldn't do
- // this for host.
- //
- // TODO(jiyong): explain why the same module is passed in twice.
- // Switching the first am to parent breaks lots of tests.
- if !android.IsDepInSameApex(ctx, am, am) {
- return false
- }
-
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- } else if rm, ok := child.(*rust.Module); ok {
- af := apexFileForRustLibrary(ctx, rm)
- af.transitiveDep = true
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- }
- } else if cc.IsTestPerSrcDepTag(depTag) {
- if cc, ok := child.(*cc.Module); ok {
- af := apexFileForExecutable(ctx, cc)
- // Handle modules created as `test_per_src` variations of a single test module:
- // use the name of the generated test binary (`fileToCopy`) instead of the name
- // of the original test module (`depName`, shared by all `test_per_src`
- // variations of that module).
- af.androidMkModuleName = filepath.Base(af.builtFile.String())
- // these are not considered transitive dep
- af.transitiveDep = false
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- }
- } else if cc.IsHeaderDepTag(depTag) {
- // nothing
- } else if java.IsJniDepTag(depTag) {
- // Because APK-in-APEX embeds jni_libs transitively, we don't need to track transitive deps
- return false
- } else if java.IsXmlPermissionsFileDepTag(depTag) {
- if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
- filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
- }
- } else if rust.IsDylibDepTag(depTag) {
- if rustm, ok := child.(*rust.Module); ok && rustm.IsInstallableToApex() {
- af := apexFileForRustLibrary(ctx, rustm)
- af.transitiveDep = true
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- }
- } else if rust.IsRlibDepTag(depTag) {
- // Rlib is statically linked, but it might have shared lib
- // dependencies. Track them.
- return true
- } else if java.IsBootclasspathFragmentContentDepTag(depTag) {
- // Add the contents of the bootclasspath fragment to the apex.
- switch child.(type) {
- case *java.Library, *java.SdkLibrary:
- javaModule := child.(javaModule)
- af := apexFileForBootclasspathFragmentContentModule(ctx, parent, javaModule)
- if !af.ok() {
- ctx.PropertyErrorf("bootclasspath_fragments", "bootclasspath_fragment content %q is not configured to be compiled into dex", depName)
- return false
- }
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- default:
- ctx.PropertyErrorf("bootclasspath_fragments", "bootclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
- }
- } else if java.IsSystemServerClasspathFragmentContentDepTag(depTag) {
- // Add the contents of the systemserverclasspath fragment to the apex.
- switch child.(type) {
- case *java.Library, *java.SdkLibrary:
- af := apexFileForJavaModule(ctx, child.(javaModule))
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- default:
- ctx.PropertyErrorf("systemserverclasspath_fragments", "systemserverclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
- }
- } else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok {
- // nothing
- } else if depTag == android.DarwinUniversalVariantTag {
- // nothing
- } else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
- ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
- }
- }
- }
- return false
- })
+ vctx := visitorContext{handleSpecialLibs: !android.Bool(a.properties.Ignore_system_library_special_case)}
+ ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool { return a.depVisitor(&vctx, ctx, child, parent) })
+ vctx.normalizeFileInfo()
if a.privateKeyFile == nil {
ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.overridableProperties.Key))
return
}
- // Remove duplicates in filesInfo
- removeDup := func(filesInfo []apexFile) []apexFile {
- encountered := make(map[string]apexFile)
- for _, f := range filesInfo {
- dest := filepath.Join(f.installDir, f.builtFile.Base())
- if e, ok := encountered[dest]; !ok {
- encountered[dest] = f
- } else {
- // If a module is directly included and also transitively depended on
- // consider it as directly included.
- e.transitiveDep = e.transitiveDep && f.transitiveDep
- encountered[dest] = e
- }
- }
- var result []apexFile
- for _, v := range encountered {
- result = append(result, v)
- }
- return result
- }
- filesInfo = removeDup(filesInfo)
-
- // Sort to have consistent build rules
- sort.Slice(filesInfo, func(i, j int) bool {
- // Sort by destination path so as to ensure consistent ordering even if the source of the files
- // changes.
- return filesInfo[i].path() < filesInfo[j].path()
- })
-
////////////////////////////////////////////////////////////////////////////////////////////
// 3) some fields in apexBundle struct are configured
a.installDir = android.PathForModuleInstall(ctx, "apex")
- a.filesInfo = filesInfo
+ a.filesInfo = vctx.filesInfo
// Set suffix and primaryApexType depending on the ApexType
buildFlattenedAsDefault := ctx.Config().FlattenApex()
@@ -2267,7 +2280,7 @@
////////////////////////////////////////////////////////////////////////////////////////////
// 4) generate the build rules to create the APEX. This is done in builder.go.
- a.buildManifest(ctx, provideNativeLibs, requireNativeLibs)
+ a.buildManifest(ctx, vctx.provideNativeLibs, vctx.requireNativeLibs)
if a.properties.ApexType == flattenedApex {
a.buildFlattenedApex(ctx)
} else {
@@ -2458,7 +2471,7 @@
android.BazelModuleBase
}
-func (o *OverrideApex) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (o *OverrideApex) GenerateAndroidBuildActions(_ android.ModuleContext) {
// All the overrides happen in the base module.
}