diff options
Diffstat (limited to 'apex/apex.go')
-rw-r--r-- | apex/apex.go | 1052 |
1 files changed, 590 insertions, 462 deletions
diff --git a/apex/apex.go b/apex/apex.go index 76af1b82e..5678b06bf 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -19,6 +19,7 @@ package apex import ( "fmt" "path/filepath" + "regexp" "sort" "strings" @@ -33,6 +34,7 @@ import ( prebuilt_etc "android/soong/etc" "android/soong/filesystem" "android/soong/java" + "android/soong/multitree" "android/soong/python" "android/soong/rust" "android/soong/sh" @@ -48,7 +50,7 @@ func registerApexBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("apex_vndk", vndkApexBundleFactory) ctx.RegisterModuleType("apex_defaults", defaultsFactory) ctx.RegisterModuleType("prebuilt_apex", PrebuiltFactory) - ctx.RegisterModuleType("override_apex", overrideApexFactory) + ctx.RegisterModuleType("override_apex", OverrideApexFactory) ctx.RegisterModuleType("apex_set", apexSetFactory) ctx.PreArchMutators(registerPreArchMutators) @@ -158,12 +160,6 @@ type apexBundleProperties struct { // or else conflicting build rules may be created. Multi_install_skip_symbol_files *bool - // List of SDKs that are used to build this APEX. A reference to an SDK should be either - // `name#version` or `name` which is an alias for `name#current`. If left empty, - // `platform#current` is implied. This value affects all modules included in this APEX. In - // other words, they are also built with the SDKs specified here. - Uses_sdks []string - // The type of APEX to build. Controls what the APEX payload is. Either 'image', 'zip' or // 'both'. When set to image, contents are stored in a filesystem image inside a zip // container. When set to zip, contents are stored in a zip container directly. This type is @@ -358,6 +354,7 @@ type apexBundle struct { android.OverridableModuleBase android.SdkBase android.BazelModuleBase + multitree.ExportableModuleBase // Properties properties apexBundleProperties @@ -611,30 +608,34 @@ type dependencyTag struct { sourceOnly bool } -func (d dependencyTag) ReplaceSourceWithPrebuilt() bool { +func (d *dependencyTag) String() string { + return fmt.Sprintf("apex.dependencyTag{%q}", d.name) +} + +func (d *dependencyTag) ReplaceSourceWithPrebuilt() bool { return !d.sourceOnly } var _ android.ReplaceSourceWithPrebuilt = &dependencyTag{} var ( - androidAppTag = dependencyTag{name: "androidApp", payload: true} - bpfTag = dependencyTag{name: "bpf", payload: true} - certificateTag = dependencyTag{name: "certificate"} - executableTag = dependencyTag{name: "executable", payload: true} - fsTag = dependencyTag{name: "filesystem", payload: true} - bcpfTag = dependencyTag{name: "bootclasspathFragment", payload: true, sourceOnly: true} - sscpfTag = dependencyTag{name: "systemserverclasspathFragment", payload: true, sourceOnly: true} - compatConfigTag = dependencyTag{name: "compatConfig", payload: true, sourceOnly: true} - javaLibTag = dependencyTag{name: "javaLib", payload: true} - jniLibTag = dependencyTag{name: "jniLib", payload: true} - keyTag = dependencyTag{name: "key"} - prebuiltTag = dependencyTag{name: "prebuilt", payload: true} - rroTag = dependencyTag{name: "rro", payload: true} - sharedLibTag = dependencyTag{name: "sharedLib", payload: true} - testForTag = dependencyTag{name: "test for"} - testTag = dependencyTag{name: "test", payload: true} - shBinaryTag = dependencyTag{name: "shBinary", payload: true} + androidAppTag = &dependencyTag{name: "androidApp", payload: true} + bpfTag = &dependencyTag{name: "bpf", payload: true} + certificateTag = &dependencyTag{name: "certificate"} + executableTag = &dependencyTag{name: "executable", payload: true} + fsTag = &dependencyTag{name: "filesystem", payload: true} + bcpfTag = &dependencyTag{name: "bootclasspathFragment", payload: true, sourceOnly: true} + sscpfTag = &dependencyTag{name: "systemserverclasspathFragment", payload: true, sourceOnly: true} + compatConfigTag = &dependencyTag{name: "compatConfig", payload: true, sourceOnly: true} + javaLibTag = &dependencyTag{name: "javaLib", payload: true} + jniLibTag = &dependencyTag{name: "jniLib", payload: true} + keyTag = &dependencyTag{name: "key"} + prebuiltTag = &dependencyTag{name: "prebuilt", payload: true} + rroTag = &dependencyTag{name: "rro", payload: true} + sharedLibTag = &dependencyTag{name: "sharedLib", payload: true} + testForTag = &dependencyTag{name: "test for"} + testTag = &dependencyTag{name: "test", payload: true} + shBinaryTag = &dependencyTag{name: "shBinary", payload: true} ) // TODO(jiyong): shorten this function signature @@ -789,19 +790,6 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { commonVariation := ctx.Config().AndroidCommonTarget.Variations() ctx.AddFarVariationDependencies(commonVariation, fsTag, a.properties.Filesystems...) ctx.AddFarVariationDependencies(commonVariation, compatConfigTag, a.properties.Compat_configs...) - - // Marks that this APEX (in fact all the modules in it) has to be built with the given SDKs. - // This field currently isn't used. - // TODO(jiyong): consider dropping this feature - // TODO(jiyong): ensure that all apexes are with non-empty uses_sdks - if len(a.properties.Uses_sdks) > 0 { - sdkRefs := []android.SdkRef{} - for _, str := range a.properties.Uses_sdks { - parsed := android.ParseSdkRef(ctx, str, "uses_sdks") - sdkRefs = append(sdkRefs, parsed) - } - a.BuildWithSdks(sdkRefs) - } } // DepsMutator for the overridden properties. @@ -966,7 +954,6 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) { apexInfo := android.ApexInfo{ ApexVariationName: apexVariationName, MinSdkVersion: minSdkVersion, - RequiredSdks: a.RequiredSdks(), Updatable: a.Updatable(), UsePlatformApis: a.UsePlatformApis(), InApexVariants: []string{apexVariationName}, @@ -994,6 +981,7 @@ type ApexInfoMutator interface { // apexInfoMutator delegates the work of identifying which modules need an ApexInfo and apex // specific variant to modules that support the ApexInfoMutator. +// It also propagates updatable=true to apps of updatable apexes func apexInfoMutator(mctx android.TopDownMutatorContext) { if !mctx.Module().Enabled() { return @@ -1001,8 +989,8 @@ func apexInfoMutator(mctx android.TopDownMutatorContext) { if a, ok := mctx.Module().(ApexInfoMutator); ok { a.ApexInfoMutator(mctx) - return } + enforceAppUpdatability(mctx) } // apexStrictUpdatibilityLintMutator propagates strict_updatability_linting to transitive deps of a mainline module @@ -1033,6 +1021,22 @@ func apexStrictUpdatibilityLintMutator(mctx android.TopDownMutatorContext) { } } +// enforceAppUpdatability propagates updatable=true to apps of updatable apexes +func enforceAppUpdatability(mctx android.TopDownMutatorContext) { + if !mctx.Module().Enabled() { + return + } + if apex, ok := mctx.Module().(*apexBundle); ok && apex.Updatable() { + // checking direct deps is sufficient since apex->apk is a direct edge, even when inherited via apex_defaults + mctx.VisitDirectDeps(func(module android.Module) { + // ignore android_test_app + if app, ok := module.(*java.AndroidApp); ok { + app.SetUpdatable(true) + } + }) + } +} + // TODO: b/215736885 Whittle the denylist // Transitive deps of certain mainline modules baseline NewApi errors // Skip these mainline modules for now @@ -1334,7 +1338,7 @@ func apexFlattenedMutator(mctx android.BottomUpMutatorContext) { 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 @@ -1359,6 +1363,21 @@ func (a *apexBundle) OutputFiles(tag string) (android.Paths, error) { } } +var _ multitree.Exportable = (*apexBundle)(nil) + +func (a *apexBundle) Exportable() bool { + if a.properties.ApexType == flattenedApex { + return false + } + return true +} + +func (a *apexBundle) TaggedOutputs() map[string]android.Paths { + ret := make(map[string]android.Paths) + ret["apex"] = android.Paths{a.outputFile} + return ret +} + var _ cc.Coverage = (*apexBundle)(nil) // Implements cc.Coverage @@ -1449,19 +1468,19 @@ func (a *apexBundle) EnableSanitizer(sanitizerName string) { } } -func (a *apexBundle) IsSanitizerEnabled(ctx android.BaseModuleContext, sanitizerName string) bool { +func (a *apexBundle) IsSanitizerEnabled(config android.Config, sanitizerName string) bool { if android.InList(sanitizerName, a.properties.SanitizerNames) { return true } // Then follow the global setting - globalSanitizerNames := []string{} + var globalSanitizerNames []string if a.Host() { - globalSanitizerNames = ctx.Config().SanitizeHost() + globalSanitizerNames = config.SanitizeHost() } else { - arches := ctx.Config().SanitizeDeviceArch() + arches := config.SanitizeDeviceArch() if len(arches) == 0 || android.InList(a.Arch().ArchType.Name, arches) { - globalSanitizerNames = ctx.Config().SanitizeDevice() + globalSanitizerNames = config.SanitizeDevice() } } return android.InList(sanitizerName, globalSanitizerNames) @@ -1656,7 +1675,20 @@ type androidApp interface { var _ androidApp = (*java.AndroidApp)(nil) var _ androidApp = (*java.AndroidAppImport)(nil) -const APEX_VERSION_PLACEHOLDER = "__APEX_VERSION_PLACEHOLDER__" +func sanitizedBuildIdForPath(ctx android.BaseModuleContext) string { + buildId := ctx.Config().BuildId() + + // The build ID is used as a suffix for a filename, so ensure that + // the set of characters being used are sanitized. + // - any word character: [a-zA-Z0-9_] + // - dots: . + // - dashes: - + validRegex := regexp.MustCompile(`^[\w\.\-\_]+$`) + if !validRegex.MatchString(buildId) { + ctx.ModuleErrorf("Unable to use build id %s as filename suffix, valid characters are [a-z A-Z 0-9 _ . -].", buildId) + } + return buildId +} func apexFileForAndroidApp(ctx android.BaseModuleContext, aapp androidApp) apexFile { appDir := "app" @@ -1667,7 +1699,7 @@ func apexFileForAndroidApp(ctx android.BaseModuleContext, aapp androidApp) apexF // TODO(b/224589412, b/226559955): Ensure that the subdirname is suffixed // so that PackageManager correctly invalidates the existing installed apk // in favour of the new APK-in-APEX. See bugs for more information. - dirInApex := filepath.Join(appDir, aapp.InstallApkName()+"@"+APEX_VERSION_PLACEHOLDER) + dirInApex := filepath.Join(appDir, aapp.InstallApkName()+"@"+sanitizedBuildIdForPath(ctx)) fileToCopy := aapp.OutputFile() af := newApexFile(ctx, fileToCopy, aapp.BaseModuleName(), dirInApex, app, aapp) @@ -1724,7 +1756,7 @@ func (a *apexBundle) WalkPayloadDeps(ctx android.ModuleContext, do android.Paylo if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok { return false } - if dt, ok := depTag.(dependencyTag); ok && !dt.payload { + if dt, ok := depTag.(*dependencyTag); ok && !dt.payload { return false } @@ -1758,6 +1790,382 @@ func (f fsType) string() string { } } +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. @@ -1780,386 +2188,23 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { //////////////////////////////////////////////////////////////////////////////////////////// // 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()+"@"+APEX_VERSION_PLACEHOLDER) - 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() @@ -2235,7 +2280,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { //////////////////////////////////////////////////////////////////////////////////////////// // 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 { @@ -2372,6 +2417,7 @@ func newApexBundle() *apexBundle { android.InitSdkAwareModule(module) android.InitOverridableModule(module, &module.overridableProperties.Overrides) android.InitBazelModule(module) + multitree.InitExportableModule(module) return module } @@ -2422,24 +2468,109 @@ func DefaultsFactory(props ...interface{}) android.Module { type OverrideApex struct { android.ModuleBase android.OverrideModuleBase + android.BazelModuleBase } -func (o *OverrideApex) GenerateAndroidBuildActions(ctx android.ModuleContext) { +func (o *OverrideApex) GenerateAndroidBuildActions(_ android.ModuleContext) { // All the overrides happen in the base module. } // override_apex is used to create an apex module based on another apex module by overriding some of // its properties. -func overrideApexFactory() android.Module { +func OverrideApexFactory() android.Module { m := &OverrideApex{} m.AddProperties(&overridableProperties{}) android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon) android.InitOverrideModule(m) + android.InitBazelModule(m) return m } +func (o *OverrideApex) ConvertWithBp2build(ctx android.TopDownMutatorContext) { + if ctx.ModuleType() != "override_apex" { + return + } + + baseApexModuleName := o.OverrideModuleBase.GetOverriddenModuleName() + baseModule, baseApexExists := ctx.ModuleFromName(baseApexModuleName) + if !baseApexExists { + panic(fmt.Errorf("Base apex module doesn't exist: %s", baseApexModuleName)) + } + + a, baseModuleIsApex := baseModule.(*apexBundle) + if !baseModuleIsApex { + panic(fmt.Errorf("Base module is not apex module: %s", baseApexModuleName)) + } + attrs, props := convertWithBp2build(a, ctx) + + for _, p := range o.GetProperties() { + overridableProperties, ok := p.(*overridableProperties) + if !ok { + continue + } + + // Manifest is either empty or a file in the directory of base APEX and is not overridable. + // After it is converted in convertWithBp2build(baseApex, ctx), + // the attrs.Manifest.Value.Label is the file path relative to the directory + // of base apex. So the following code converts it to a label that looks like + // <package of base apex>:<path of manifest file> if base apex and override + // apex are not in the same package. + baseApexPackage := ctx.OtherModuleDir(a) + overrideApexPackage := ctx.ModuleDir() + if baseApexPackage != overrideApexPackage { + attrs.Manifest.Value.Label = "//" + baseApexPackage + ":" + attrs.Manifest.Value.Label + } + + // Key + if overridableProperties.Key != nil { + attrs.Key = bazel.LabelAttribute{} + attrs.Key.SetValue(android.BazelLabelForModuleDepSingle(ctx, *overridableProperties.Key)) + } + + // Certificate + if overridableProperties.Certificate != nil { + attrs.Certificate = bazel.LabelAttribute{} + attrs.Certificate.SetValue(android.BazelLabelForModuleDepSingle(ctx, *overridableProperties.Certificate)) + } + + // Prebuilts + if overridableProperties.Prebuilts != nil { + prebuiltsLabelList := android.BazelLabelForModuleDeps(ctx, overridableProperties.Prebuilts) + attrs.Prebuilts = bazel.MakeLabelListAttribute(prebuiltsLabelList) + } + + // Compressible + if overridableProperties.Compressible != nil { + attrs.Compressible = bazel.BoolAttribute{Value: overridableProperties.Compressible} + } + + // Package name + // + // e.g. com.android.adbd's package name is com.android.adbd, but + // com.google.android.adbd overrides the package name to com.google.android.adbd + // + // TODO: this can be overridden from the product configuration, see + // getOverrideManifestPackageName and + // PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES. + // + // Instead of generating the BUILD files differently based on the product config + // at the point of conversion, this should be handled by the BUILD file loading + // from the soong_injection's product_vars, so product config is decoupled from bp2build. + if overridableProperties.Package_name != "" { + attrs.Package_name = &overridableProperties.Package_name + } + + // Logging parent + if overridableProperties.Logging_parent != "" { + attrs.Logging_parent = &overridableProperties.Logging_parent + } + } + + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: o.Name()}, &attrs) +} + /////////////////////////////////////////////////////////////////////////////////////////////////// // Vality check routines // @@ -2678,7 +2809,7 @@ func (a *apexBundle) checkStaticExecutables(ctx android.ModuleContext) { // A small list of exceptions where static executables are allowed in APEXes. func isStaticExecutableAllowed(apex string, exec string) bool { m := map[string][]string{ - "com.android.runtime": []string{ + "com.android.runtime": { "linker", "linkerconfig", }, @@ -3143,33 +3274,6 @@ func makeApexAvailableBaseline() map[string][]string { // // Module separator // - m["com.android.permission"] = []string{ - "car-ui-lib", - "iconloader", - "kotlin-annotations", - "kotlin-stdlib", - "kotlin-stdlib-jdk7", - "kotlin-stdlib-jdk8", - "kotlinx-coroutines-android", - "kotlinx-coroutines-android-nodeps", - "kotlinx-coroutines-core", - "kotlinx-coroutines-core-nodeps", - "permissioncontroller-statsd", - "GooglePermissionController", - "PermissionController", - "SettingsLibActionBarShadow", - "SettingsLibAppPreference", - "SettingsLibBarChartPreference", - "SettingsLibLayoutPreference", - "SettingsLibProgressBar", - "SettingsLibSearchWidget", - "SettingsLibSettingsTheme", - "SettingsLibRestrictedLockUtils", - "SettingsLibHelpUtils", - } - // - // Module separator - // m["com.android.runtime"] = []string{ "bionic_libc_platform_headers", "libarm-optimized-routines-math", @@ -3342,11 +3446,11 @@ func createBcpPermittedPackagesRules(bcpPermittedPackages map[string][]string) [ // Adding code to the bootclasspath in new packages will cause issues on module update. func qBcpPackages() map[string][]string { return map[string][]string{ - "conscrypt": []string{ + "conscrypt": { "android.net.ssl", "com.android.org.conscrypt", }, - "updatable-media": []string{ + "updatable-media": { "android.media", }, } @@ -3356,32 +3460,32 @@ func qBcpPackages() map[string][]string { // Adding code to the bootclasspath in new packages will cause issues on module update. func rBcpPackages() map[string][]string { return map[string][]string{ - "framework-mediaprovider": []string{ + "framework-mediaprovider": { "android.provider", }, - "framework-permission": []string{ + "framework-permission": { "android.permission", "android.app.role", "com.android.permission", "com.android.role", }, - "framework-sdkextensions": []string{ + "framework-sdkextensions": { "android.os.ext", }, - "framework-statsd": []string{ + "framework-statsd": { "android.app", "android.os", "android.util", "com.android.internal.statsd", "com.android.server.stats", }, - "framework-wifi": []string{ + "framework-wifi": { "com.android.server.wifi", "com.android.wifi.x", "android.hardware.wifi", "android.net.wifi", }, - "framework-tethering": []string{ + "framework-tethering": { "android.net", }, } @@ -3403,6 +3507,8 @@ type bazelApexBundleAttributes struct { Native_shared_libs_32 bazel.LabelListAttribute Native_shared_libs_64 bazel.LabelListAttribute Compressible bazel.BoolAttribute + Package_name *string + Logging_parent *string } type convertedNativeSharedLibs struct { @@ -3417,10 +3523,13 @@ func (a *apexBundle) ConvertWithBp2build(ctx android.TopDownMutatorContext) { return } + attrs, props := convertWithBp2build(a, ctx) + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: a.Name()}, &attrs) +} + +func convertWithBp2build(a *apexBundle, ctx android.TopDownMutatorContext) (bazelApexBundleAttributes, bazel.BazelTargetModuleProperties) { var manifestLabelAttribute bazel.LabelAttribute - if a.properties.Manifest != nil { - manifestLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *a.properties.Manifest)) - } + manifestLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))) var androidManifestLabelAttribute bazel.LabelAttribute if a.properties.AndroidManifest != nil { @@ -3428,8 +3537,15 @@ func (a *apexBundle) ConvertWithBp2build(ctx android.TopDownMutatorContext) { } var fileContextsLabelAttribute bazel.LabelAttribute - if a.properties.File_contexts != nil { + if a.properties.File_contexts == nil { + // See buildFileContexts(), if file_contexts is not specified the default one is used, which is //system/sepolicy/apex:<module name>-file_contexts + fileContextsLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, a.Name()+"-file_contexts")) + } else if strings.HasPrefix(*a.properties.File_contexts, ":") { + // File_contexts is a module fileContextsLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *a.properties.File_contexts)) + } else { + // File_contexts is a file + fileContextsLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *a.properties.File_contexts)) } // TODO(b/219503907) this would need to be set to a.MinSdkVersionValue(ctx) but @@ -3487,7 +3603,17 @@ func (a *apexBundle) ConvertWithBp2build(ctx android.TopDownMutatorContext) { compressibleAttribute.Value = a.overridableProperties.Compressible } - attrs := &bazelApexBundleAttributes{ + var packageName *string + if a.overridableProperties.Package_name != "" { + packageName = &a.overridableProperties.Package_name + } + + var loggingParent *string + if a.overridableProperties.Logging_parent != "" { + loggingParent = &a.overridableProperties.Logging_parent + } + + attrs := bazelApexBundleAttributes{ Manifest: manifestLabelAttribute, Android_manifest: androidManifestLabelAttribute, File_contexts: fileContextsLabelAttribute, @@ -3501,14 +3627,16 @@ func (a *apexBundle) ConvertWithBp2build(ctx android.TopDownMutatorContext) { Binaries: binariesLabelListAttribute, Prebuilts: prebuiltsLabelListAttribute, Compressible: compressibleAttribute, + Package_name: packageName, + Logging_parent: loggingParent, } props := bazel.BazelTargetModuleProperties{ Rule_class: "apex", - Bzl_load_location: "//build/bazel/rules:apex.bzl", + Bzl_load_location: "//build/bazel/rules/apex:apex.bzl", } - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: a.Name()}, attrs) + return attrs, props } // The following conversions are based on this table where the rows are the compile_multilib |