diff options
Diffstat (limited to 'java/app.go')
| -rw-r--r--[-rwxr-xr-x] | java/app.go | 779 |
1 files changed, 536 insertions, 243 deletions
diff --git a/java/app.go b/java/app.go index 706f99a83..19dc8d5d1 100755..100644 --- a/java/app.go +++ b/java/app.go @@ -18,23 +18,42 @@ package java // related module types, including their override variants. import ( + "fmt" "path/filepath" "strings" + "android/soong/testing" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" "android/soong/android" - "android/soong/bazel" "android/soong/cc" "android/soong/dexpreopt" + "android/soong/genrule" "android/soong/tradefed" ) func init() { RegisterAppBuildComponents(android.InitRegistrationContext) + pctx.HostBinToolVariable("ModifyAllowlistCmd", "modify_permissions_allowlist") } +var ( + modifyAllowlist = pctx.AndroidStaticRule("modifyAllowlist", + blueprint.RuleParams{ + Command: "${ModifyAllowlistCmd} $in $packageName $out", + CommandDeps: []string{"${ModifyAllowlistCmd}"}, + }, "packageName") +) + +type FlagsPackages struct { + // Paths to the aconfig dump output text files that are consumed by aapt2 + AconfigTextFiles android.Paths +} + +var FlagsPackagesProvider = blueprint.NewProvider[FlagsPackages]() + func RegisterAppBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("android_app", AndroidAppFactory) ctx.RegisterModuleType("android_test", AndroidTestFactory) @@ -115,6 +134,19 @@ type appProperties struct { // Prefer using other specific properties if build behaviour must be changed; avoid using this // flag for anything but neverallow rules (unless the behaviour change is invisible to owners). Updatable *bool + + // Specifies the file that contains the allowlist for this app. + Privapp_allowlist *string `android:"path"` + + // If set, create an RRO package which contains only resources having PRODUCT_CHARACTERISTICS + // and install the RRO package to /product partition, instead of passing --product argument + // to aapt2. Default is false. + // Setting this will make this APK identical to all targets, regardless of + // PRODUCT_CHARACTERISTICS. + Generate_product_characteristics_rro *bool + + ProductCharacteristicsRROPackageName *string `blueprint:"mutated"` + ProductCharacteristicsRROManifestModuleName *string `blueprint:"mutated"` } // android_app properties that can be overridden by override_android_app @@ -147,7 +179,6 @@ type overridableAppProperties struct { } type AndroidApp struct { - android.BazelModuleBase Library aapt android.OverridableModuleBase @@ -179,18 +210,16 @@ type AndroidApp struct { android.ApexBundleDepsInfo javaApiUsedByOutputFile android.ModuleOutPath + + privAppAllowlist android.OptionalPath } func (a *AndroidApp) IsInstallable() bool { return Bool(a.properties.Installable) } -func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths { - return nil -} - -func (a *AndroidApp) ExportedStaticPackages() android.Paths { - return nil +func (a *AndroidApp) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] { + return a.aapt.resourcesNodesDepSet } func (a *AndroidApp) OutputFile() android.Path { @@ -205,6 +234,10 @@ func (a *AndroidApp) JniCoverageOutputs() android.Paths { return a.jniCoverageOutputs } +func (a *AndroidApp) PrivAppAllowlist() android.OptionalPath { + return a.privAppAllowlist +} + var _ AndroidLibraryDependency = (*AndroidApp)(nil) type Certificate struct { @@ -223,13 +256,13 @@ func (c Certificate) AndroidMkString() string { } func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { - a.Module.deps(ctx) - if String(a.appProperties.Stl) == "c++_shared" && !a.SdkVersion(ctx).Specified() { ctx.PropertyErrorf("stl", "sdk_version must be set in order to use c++_shared") } sdkDep := decodeSdkDep(ctx, android.SdkContext(a)) + a.usesLibrary.deps(ctx, sdkDep.hasFrameworkLibs()) + a.Module.deps(ctx) if sdkDep.hasFrameworkLibs() { a.aapt.deps(ctx, sdkDep) } @@ -248,19 +281,41 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { variation := append(jniTarget.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"}) - // If the app builds against an Android SDK use the SDK variant of JNI dependencies - // unless jni_uses_platform_apis is set. - // Don't require the SDK variant for apps that are shipped on vendor, etc., as they already - // have stable APIs through the VNDK. - if (usesSDK && !a.RequiresStableAPIs(ctx) && - !Bool(a.appProperties.Jni_uses_platform_apis)) || - Bool(a.appProperties.Jni_uses_sdk_apis) { + // Test whether to use the SDK variant or the non-SDK variant of JNI dependencies. + // Many factors are considered here. + // 1. Basically, the selection follows whether the app has sdk_version set or not. + jniUsesSdkVariant := usesSDK + // 2. However, jni_uses_platform_apis and jni_uses_sdk_apis can override it + if Bool(a.appProperties.Jni_uses_sdk_apis) { + jniUsesSdkVariant = true + } + if Bool(a.appProperties.Jni_uses_platform_apis) { + jniUsesSdkVariant = false + } + // 3. Then the use of SDK variant is again prohibited for the following cases: + // 3.1. the app is shipped on unbundled partitions like vendor. Since the entire + // partition (not only the app) is considered unbudled, there's no need to use the + // SDK variant. + // 3.2. the app doesn't support embedding the JNI libs + if a.RequiresStableAPIs(ctx) || !a.shouldEmbedJnis(ctx) { + jniUsesSdkVariant = false + } + if jniUsesSdkVariant { variation = append(variation, blueprint.Variation{Mutator: "sdk", Variation: "sdk"}) } - ctx.AddFarVariationDependencies(variation, jniLibTag, a.appProperties.Jni_libs...) - } - a.usesLibrary.deps(ctx, sdkDep.hasFrameworkLibs()) + // Use the installable dep tag when the JNIs are not embedded + var tag dependencyTag + if a.shouldEmbedJnis(ctx) { + tag = jniLibTag + } else { + tag = jniInstallTag + } + ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...) + } + for _, aconfig_declaration := range a.aaptProperties.Flags_packages { + ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration) + } } func (a *AndroidApp) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) { @@ -269,6 +324,16 @@ func (a *AndroidApp) OverridablePropertiesDepsMutator(ctx android.BottomUpMutato ctx.AddDependency(ctx.Module(), certificateTag, cert) } + if a.appProperties.Privapp_allowlist != nil && !Bool(a.appProperties.Privileged) { + // There are a few uids that are explicitly considered privileged regardless of their + // app's location. Bluetooth is one such app. It should arguably be moved to priv-app, + // but for now, allow it not to be in priv-app. + privilegedBecauseOfUid := ctx.ModuleName() == "Bluetooth" + if !privilegedBecauseOfUid { + ctx.PropertyErrorf("privapp_allowlist", "privileged must be set in order to use privapp_allowlist (with a few exceptions)") + } + } + for _, cert := range a.appProperties.Additional_certificates { cert = android.SrcIsModule(cert) if cert != "" { @@ -280,12 +345,52 @@ func (a *AndroidApp) OverridablePropertiesDepsMutator(ctx android.BottomUpMutato } } +// TODO(b/156476221): Remove this allowlist +var ( + missingMinSdkVersionMtsAllowlist = []string{ + "CellBroadcastReceiverGoogleUnitTests", + "CellBroadcastReceiverUnitTests", + "CtsBatterySavingTestCases", + "CtsDeviceAndProfileOwnerApp23", + "CtsDeviceAndProfileOwnerApp30", + "CtsIntentSenderApp", + "CtsJobSchedulerTestCases", + "CtsMimeMapTestCases", + "CtsTareTestCases", + "LibStatsPullTests", + "MediaProviderClientTests", + "TeleServiceTests", + "TestExternalImsServiceApp", + "TestSmsRetrieverApp", + "TetheringPrivilegedTests", + } +) + +func checkMinSdkVersionMts(ctx android.ModuleContext, minSdkVersion android.ApiLevel) { + if includedInMts(ctx.Module()) && !minSdkVersion.Specified() && !android.InList(ctx.ModuleName(), missingMinSdkVersionMtsAllowlist) { + ctx.PropertyErrorf("min_sdk_version", "min_sdk_version is a required property for tests included in MTS") + } +} + func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { + checkMinSdkVersionMts(ctx, a.MinSdkVersion(ctx)) + applicationId := a.appTestHelperAppProperties.Manifest_values.ApplicationId + if applicationId != nil { + if a.overridableAppProperties.Package_name != nil { + ctx.PropertyErrorf("manifest_values.applicationId", "property is not supported when property package_name is set.") + } + a.aapt.manifestValues.applicationId = *applicationId + } a.generateAndroidBuildActions(ctx) + android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ + TestOnly: true, + }) + } func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.checkAppSdkVersions(ctx) + a.checkEmbedJnis(ctx) a.generateAndroidBuildActions(ctx) a.generateJavaUsedByApex(ctx) } @@ -295,7 +400,7 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { if !a.SdkVersion(ctx).Stable() { ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.SdkVersion(ctx)) } - if String(a.deviceProperties.Min_sdk_version) == "" { + if String(a.overridableProperties.Min_sdk_version) == "" { ctx.PropertyErrorf("updatable", "updatable apps must set min_sdk_version.") } @@ -319,6 +424,17 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { a.checkSdkVersions(ctx) } +// Ensures that use_embedded_native_libs are set for apk-in-apex +func (a *AndroidApp) checkEmbedJnis(ctx android.BaseModuleContext) { + apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) + apkInApex := !apexInfo.IsForPlatform() + hasJnis := len(a.appProperties.Jni_libs) > 0 + + if apkInApex && hasJnis && !Bool(a.appProperties.Use_embedded_native_libs) { + ctx.ModuleErrorf("APK in APEX should have use_embedded_native_libs: true") + } +} + // If an updatable APK sets min_sdk_version, min_sdk_vesion of JNI libs should match with it. // This check is enforced for "updatable" APKs (including APK-in-APEX). func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion android.ApiLevel) { @@ -349,7 +465,7 @@ func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool { ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.MinSdkVersion(ctx), err) } - apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) + apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) return (minSdkVersion.FinalOrFutureInt() >= 23 && Bool(a.appProperties.Use_embedded_native_libs)) || !apexInfo.IsForPlatform() } @@ -370,13 +486,13 @@ func (a *AndroidApp) shouldUncompressDex(ctx android.ModuleContext) bool { return false } - return shouldUncompressDex(ctx, &a.dexpreopter) + return shouldUncompressDex(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), &a.dexpreopter) } func (a *AndroidApp) shouldEmbedJnis(ctx android.BaseModuleContext) bool { - apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) return ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs) || - !apexInfo.IsForPlatform() || a.appProperties.AlwaysPackageNativeLibs + Bool(a.appProperties.Updatable) || + a.appProperties.AlwaysPackageNativeLibs } func generateAaptRenamePackageFlags(packageName string, renameResourcesPackage bool) []string { @@ -396,6 +512,30 @@ func (a *AndroidApp) renameResourcesPackage() bool { return proptools.BoolDefault(a.overridableAppProperties.Rename_resources_package, true) } +func getAconfigFilePaths(ctx android.ModuleContext) (aconfigTextFilePaths android.Paths) { + ctx.VisitDirectDeps(func(dep android.Module) { + tag := ctx.OtherModuleDependencyTag(dep) + switch tag { + case staticLibTag: + if flagPackages, ok := android.OtherModuleProvider(ctx, dep, FlagsPackagesProvider); ok { + aconfigTextFilePaths = append(aconfigTextFilePaths, flagPackages.AconfigTextFiles...) + } + + case aconfigDeclarationTag: + if provider, ok := android.OtherModuleProvider(ctx, dep, android.AconfigDeclarationsProviderKey); ok { + aconfigTextFilePaths = append(aconfigTextFilePaths, provider.IntermediateDumpOutputPath) + } else { + ctx.ModuleErrorf("Only aconfig_declarations module type is allowed for "+ + "flags_packages property, but %s is not aconfig_declarations module type", + dep.Name(), + ) + } + } + }) + + return android.FirstUniquePaths(aconfigTextFilePaths) +} + func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { usePlatformAPI := proptools.Bool(a.Module.deviceProperties.Platform_apis) if ctx.Module().(android.SdkContext).SdkVersion(ctx).Kind == android.SdkModule { @@ -409,9 +549,11 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { aaptLinkFlags := []string{} // Add TARGET_AAPT_CHARACTERISTICS values to AAPT link flags if they exist and --product flags were not provided. + autogenerateRRO := proptools.Bool(a.appProperties.Generate_product_characteristics_rro) hasProduct := android.PrefixInList(a.aaptProperties.Aaptflags, "--product") - if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 { - aaptLinkFlags = append(aaptLinkFlags, "--product", ctx.Config().ProductAAPTCharacteristics()) + characteristics := ctx.Config().ProductAAPTCharacteristics() + if !autogenerateRRO && !hasProduct && len(characteristics) > 0 && characteristics != "default" { + aaptLinkFlags = append(aaptLinkFlags, "--product", characteristics) } if !Bool(a.aaptProperties.Aapt_include_all_resources) { @@ -441,27 +583,59 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { a.aapt.splitNames = a.appProperties.Package_splits a.aapt.LoggingParent = String(a.overridableAppProperties.Logging_parent) if a.Updatable() { - a.aapt.defaultManifestVersion = android.DefaultUpdatableModuleVersion + if override := ctx.Config().Getenv("OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION"); override != "" { + a.aapt.defaultManifestVersion = override + } else { + a.aapt.defaultManifestVersion = android.DefaultUpdatableModuleVersion + } } - a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts, - a.usesLibraryProperties.Exclude_uses_libs, a.enforceDefaultTargetSdkVersion(), aaptLinkFlags...) + + // Use non final ids if we are doing optimized shrinking and are using R8. + nonFinalIds := a.dexProperties.optimizedResourceShrinkingEnabled(ctx) && a.dexer.effectiveOptimizeEnabled() + + aconfigTextFilePaths := getAconfigFilePaths(ctx) + + a.aapt.buildActions(ctx, + aaptBuildActionOptions{ + sdkContext: android.SdkContext(a), + classLoaderContexts: a.classLoaderContexts, + excludedLibs: a.usesLibraryProperties.Exclude_uses_libs, + enforceDefaultTargetSdkVersion: a.enforceDefaultTargetSdkVersion(), + forceNonFinalResourceIDs: nonFinalIds, + extraLinkFlags: aaptLinkFlags, + aconfigTextFiles: aconfigTextFilePaths, + usesLibrary: &a.usesLibrary, + }, + ) // apps manifests are handled by aapt, don't let Module see them a.properties.Manifest = nil + + android.SetProvider(ctx, FlagsPackagesProvider, FlagsPackages{ + AconfigTextFiles: aconfigTextFilePaths, + }) } func (a *AndroidApp) proguardBuildActions(ctx android.ModuleContext) { var staticLibProguardFlagFiles android.Paths ctx.VisitDirectDeps(func(m android.Module) { - if lib, ok := m.(LibraryDependency); ok && ctx.OtherModuleDependencyTag(m) == staticLibTag { - staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, lib.ExportedProguardFlagFiles()...) + depProguardInfo, _ := android.OtherModuleProvider(ctx, m, ProguardSpecInfoProvider) + staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, depProguardInfo.UnconditionallyExportedProguardFlags.ToList()...) + if ctx.OtherModuleDependencyTag(m) == staticLibTag { + staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, depProguardInfo.ProguardFlagsFiles.ToList()...) } }) staticLibProguardFlagFiles = android.FirstUniquePaths(staticLibProguardFlagFiles) - a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles, staticLibProguardFlagFiles...) - a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles, a.proguardOptionsFile) + a.Module.extraProguardFlagsFiles = append(a.Module.extraProguardFlagsFiles, staticLibProguardFlagFiles...) + if !(a.dexProperties.optimizedResourceShrinkingEnabled(ctx)) { + // When using the optimized shrinking the R8 enqueuer will traverse the xml files that become + // live for code references and (transitively) mark these as live. + // In this case we explicitly don't wan't the aapt2 generated keep files (which would keep the now + // dead code alive) + a.Module.extraProguardFlagsFiles = append(a.Module.extraProguardFlagsFiles, a.proguardOptionsFile) + } } func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath { @@ -478,7 +652,7 @@ func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath return android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk") } -func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { +func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) (android.Path, android.Path) { a.dexpreopter.installPath = a.installPath(ctx) a.dexpreopter.isApp = true if a.dexProperties.Uncompress_dex == nil { @@ -491,11 +665,40 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { a.dexpreopter.manifestFile = a.mergedManifestFile a.dexpreopter.preventInstall = a.appProperties.PreventInstall + var packageResources = a.exportPackage + if ctx.ModuleName() != "framework-res" { - a.Module.compile(ctx, a.aaptSrcJar) + if a.dexProperties.resourceShrinkingEnabled(ctx) { + protoFile := android.PathForModuleOut(ctx, packageResources.Base()+".proto.apk") + aapt2Convert(ctx, protoFile, packageResources, "proto") + a.dexer.resourcesInput = android.OptionalPathForPath(protoFile) + } + + var extraSrcJars android.Paths + var extraClasspathJars android.Paths + var extraCombinedJars android.Paths + if a.useResourceProcessorBusyBox(ctx) { + // When building an app with ResourceProcessorBusyBox enabled ResourceProcessorBusyBox has already + // created R.class files that provide IDs for resources in busybox/R.jar. Pass that file in the + // classpath when compiling everything else, and add it to the final classes jar. + extraClasspathJars = android.Paths{a.aapt.rJar} + extraCombinedJars = android.Paths{a.aapt.rJar} + } else { + // When building an app without ResourceProcessorBusyBox the aapt2 rule creates R.srcjar containing + // R.java files for the app's package and the packages from all transitive static android_library + // dependencies. Compile the srcjar alongside the rest of the sources. + extraSrcJars = android.Paths{a.aapt.aaptSrcJar} + } + + a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars) + if a.dexProperties.resourceShrinkingEnabled(ctx) { + binaryResources := android.PathForModuleOut(ctx, packageResources.Base()+".binary.out.apk") + aapt2Convert(ctx, binaryResources, a.dexer.resourcesOutput.Path(), "binary") + packageResources = binaryResources + } } - return a.dexJarFile.PathOrNil() + return a.dexJarFile.PathOrNil(), packageResources } func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, prebuiltJniPackages android.Paths, ctx android.ModuleContext) android.WritablePath { @@ -591,7 +794,6 @@ func processMainCert(m android.ModuleBase, certPropValue string, certificates [] } } - return mainCertificate, certificates } @@ -599,18 +801,57 @@ func (a *AndroidApp) InstallApkName() string { return a.installApkName } +func (a *AndroidApp) createPrivappAllowlist(ctx android.ModuleContext) android.Path { + if a.appProperties.Privapp_allowlist == nil { + return nil + } + + isOverrideApp := a.GetOverriddenBy() != "" + if !isOverrideApp { + // if this is not an override, we don't need to rewrite the existing privapp allowlist + return android.PathForModuleSrc(ctx, *a.appProperties.Privapp_allowlist) + } + + if a.overridableAppProperties.Package_name == nil { + ctx.PropertyErrorf("privapp_allowlist", "package_name must be set to use privapp_allowlist") + } + + packageName := *a.overridableAppProperties.Package_name + fileName := "privapp_allowlist_" + packageName + ".xml" + outPath := android.PathForModuleOut(ctx, fileName).OutputPath + ctx.Build(pctx, android.BuildParams{ + Rule: modifyAllowlist, + Input: android.PathForModuleSrc(ctx, *a.appProperties.Privapp_allowlist), + Output: outPath, + Args: map[string]string{ + "packageName": packageName, + }, + }) + return &outPath +} + func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { var apkDeps android.Paths - if !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() { + apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) + if !apexInfo.IsForPlatform() { a.hideApexVariantFromMake = true } a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx) a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex) + // Unlike installApkName, a.stem should respect base module name for override_android_app. + // Therefore, use ctx.ModuleName() instead of a.Name(). + a.stem = proptools.StringDefault(a.overridableProperties.Stem, ctx.ModuleName()) + // Check if the install APK name needs to be overridden. - a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(a.Stem()) + // Both android_app and override_android_app module are expected to possess + // its module bound apk path. However, override_android_app inherits ctx.ModuleName() + // from the base module. Therefore, use a.Name() which represents + // the module name for both android_app and override_android_app. + a.installApkName = ctx.DeviceConfig().OverridePackageNameFor( + proptools.StringDefault(a.overridableProperties.Stem, a.Name())) if ctx.ModuleName() == "framework-res" { // framework-res.apk is installed as system/framework/framework-res.apk @@ -625,6 +866,9 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.onDeviceDir = android.InstallPathToOnDevicePath(ctx, a.installDir) a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx) + if a.usesLibrary.shouldDisableDexpreopt { + a.dexpreopter.disableDexpreopt() + } var noticeAssetPath android.WritablePath if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") { @@ -643,22 +887,13 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { // Process all building blocks, from AAPT to certificates. a.aaptBuildActions(ctx) - // The decision to enforce <uses-library> checks is made before adding implicit SDK libraries. a.usesLibrary.freezeEnforceUsesLibraries() - // Add implicit SDK libraries to <uses-library> list. - requiredUsesLibs, optionalUsesLibs := a.classLoaderContexts.UsesLibs() - for _, usesLib := range requiredUsesLibs { - a.usesLibrary.addLib(usesLib, false) - } - for _, usesLib := range optionalUsesLibs { - a.usesLibrary.addLib(usesLib, true) - } - // Check that the <uses-library> list is coherent with the manifest. if a.usesLibrary.enforceUsesLibraries() { - manifestCheckFile := a.usesLibrary.verifyUsesLibrariesManifest(ctx, a.mergedManifestFile) + manifestCheckFile := a.usesLibrary.verifyUsesLibrariesManifest( + ctx, a.mergedManifestFile, &a.classLoaderContexts) apkDeps = append(apkDeps, manifestCheckFile) } @@ -669,9 +904,11 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.linter.resources = a.aapt.resourceFiles a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps() - dexJarFile := a.dexBuildActions(ctx) + dexJarFile, packageResources := a.dexBuildActions(ctx) - jniLibs, prebuiltJniPackages, certificates := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis)) + // No need to check the SDK version of the JNI deps unless we embed them + checkNativeSdkVersion := a.shouldEmbedJnis(ctx) && !Bool(a.appProperties.Jni_uses_platform_apis) + jniLibs, prebuiltJniPackages, certificates := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), checkNativeSdkVersion) jniJarFile := a.jniBuildActions(jniLibs, prebuiltJniPackages, ctx) if ctx.Failed() { @@ -693,7 +930,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { } rotationMinSdkVersion := String(a.overridableAppProperties.RotationMinSdkVersion) - CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion, Bool(a.dexProperties.Optimize.Shrink_resources)) + CreateAndSignAppPackage(ctx, packageFile, packageResources, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion) a.outputFile = packageFile if v4SigningRequested { a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile) @@ -722,7 +959,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { if v4SigningRequested { v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk.idsig") } - CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion, false) + CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion) a.extraOutputFiles = append(a.extraOutputFiles, packageFile) if v4SigningRequested { a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile) @@ -734,21 +971,68 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { BuildBundleModule(ctx, bundleFile, a.exportPackage, jniJarFile, dexJarFile) a.bundleFile = bundleFile - apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) + allowlist := a.createPrivappAllowlist(ctx) + if allowlist != nil { + a.privAppAllowlist = android.OptionalPathForPath(allowlist) + } // Install the app package. - if (Bool(a.Module.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() && - !a.appProperties.PreventInstall { + shouldInstallAppPackage := (Bool(a.Module.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() && !a.appProperties.PreventInstall + if shouldInstallAppPackage { + if a.privAppAllowlist.Valid() { + allowlistInstallPath := android.PathForModuleInstall(ctx, "etc", "permissions") + allowlistInstallFilename := a.installApkName + ".xml" + ctx.InstallFile(allowlistInstallPath, allowlistInstallFilename, a.privAppAllowlist.Path()) + } - var extraInstalledPaths android.Paths + var extraInstalledPaths android.InstallPaths for _, extra := range a.extraOutputFiles { installed := ctx.InstallFile(a.installDir, extra.Base(), extra) extraInstalledPaths = append(extraInstalledPaths, installed) } + // If we don't embed jni libs, make sure that those are installed along with the + // app, and also place symlinks to the installed paths under the lib/<arch> + // directory of the app installation directory. ex: + // /system/app/MyApp/lib/arm64/libfoo.so -> /system/lib64/libfoo.so + if !a.embeddedJniLibs { + for _, jniLib := range jniLibs { + archStr := jniLib.target.Arch.ArchType.String() + symlinkDir := a.installDir.Join(ctx, "lib", archStr) + for _, installedLib := range jniLib.installPaths { + // install the symlink itself + symlinkName := installedLib.Base() + symlinkTarget := android.InstallPathToOnDevicePath(ctx, installedLib) + ctx.InstallAbsoluteSymlink(symlinkDir, symlinkName, symlinkTarget) + } + } + } ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...) } a.buildAppDependencyInfo(ctx) + + providePrebuiltInfo(ctx, + prebuiltInfoProps{ + baseModuleName: a.BaseModuleName(), + isPrebuilt: false, + }, + ) + + a.setOutputFiles(ctx) +} + +func (a *AndroidApp) setOutputFiles(ctx android.ModuleContext) { + ctx.SetOutputFiles([]android.Path{a.proguardOptionsFile}, ".aapt.proguardOptionsFile") + if a.aaptSrcJar != nil { + ctx.SetOutputFiles([]android.Path{a.aaptSrcJar}, ".aapt.srcjar") + } + if a.rJar != nil { + ctx.SetOutputFiles([]android.Path{a.rJar}, ".aapt.jar") + } + ctx.SetOutputFiles([]android.Path{a.outputFile}, ".apk") + ctx.SetOutputFiles([]android.Path{a.exportPackage}, ".export-package.apk") + ctx.SetOutputFiles([]android.Path{a.aapt.manifestPath}, ".manifest.xml") + setOutputFiles(ctx, a.Library.Module) } type appDepsInterface interface { @@ -761,15 +1045,39 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, shouldCollectRecursiveNativeDeps bool, checkNativeSdkVersion bool) ([]jniLib, android.Paths, []Certificate) { - var jniLibs []jniLib - var prebuiltJniPackages android.Paths - var certificates []Certificate - seenModulePaths := make(map[string]bool) - if checkNativeSdkVersion { checkNativeSdkVersion = app.SdkVersion(ctx).Specified() && app.SdkVersion(ctx).Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx) } + jniLib, prebuiltJniPackages := collectJniDeps(ctx, shouldCollectRecursiveNativeDeps, + checkNativeSdkVersion, func(dep cc.LinkableInterface) bool { + return !dep.IsNdk(ctx.Config()) && !dep.IsStubs() + }) + + var certificates []Certificate + + ctx.VisitDirectDeps(func(module android.Module) { + otherName := ctx.OtherModuleName(module) + tag := ctx.OtherModuleDependencyTag(module) + + if tag == certificateTag { + if dep, ok := module.(*AndroidAppCertificate); ok { + certificates = append(certificates, dep.Certificate) + } else { + ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", otherName) + } + } + }) + return jniLib, prebuiltJniPackages, certificates +} + +func collectJniDeps(ctx android.ModuleContext, + shouldCollectRecursiveNativeDeps bool, + checkNativeSdkVersion bool, + filter func(cc.LinkableInterface) bool) ([]jniLib, android.Paths) { + var jniLibs []jniLib + var prebuiltJniPackages android.Paths + seenModulePaths := make(map[string]bool) ctx.WalkDeps(func(module android.Module, parent android.Module) bool { otherName := ctx.OtherModuleName(module) @@ -777,7 +1085,7 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, if IsJniDepTag(tag) || cc.IsSharedDepTag(tag) { if dep, ok := module.(cc.LinkableInterface); ok { - if dep.IsNdk(ctx.Config()) || dep.IsStubs() { + if filter != nil && !filter(dep) { return false } @@ -801,6 +1109,7 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, coverageFile: dep.CoverageOutputFile(), unstrippedFile: dep.UnstrippedOutputFile(), partition: dep.Partition(), + installPaths: dep.FilesToInstall(), }) } else if ctx.Config().AllowMissingDependencies() { ctx.AddMissingDependencies([]string{otherName}) @@ -814,22 +1123,14 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, return shouldCollectRecursiveNativeDeps } - if info, ok := ctx.OtherModuleProvider(module, JniPackageProvider).(JniPackageInfo); ok { + if info, ok := android.OtherModuleProvider(ctx, module, JniPackageProvider); ok { prebuiltJniPackages = append(prebuiltJniPackages, info.JniPackages...) } - if tag == certificateTag { - if dep, ok := module.(*AndroidAppCertificate); ok { - certificates = append(certificates, dep.Certificate) - } else { - ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", otherName) - } - } - return false }) - return jniLibs, prebuiltJniPackages, certificates + return jniLibs, prebuiltJniPackages } func (a *AndroidApp) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) { @@ -922,22 +1223,11 @@ func (a *AndroidApp) DepIsInSameApex(ctx android.BaseModuleContext, dep android. return a.Library.DepIsInSameApex(ctx, dep) } -// For OutputFileProducer interface -func (a *AndroidApp) OutputFiles(tag string) (android.Paths, error) { - switch tag { - case ".aapt.srcjar": - return []android.Path{a.aaptSrcJar}, nil - case ".export-package.apk": - return []android.Path{a.exportPackage}, nil - } - return a.Library.OutputFiles(tag) -} - func (a *AndroidApp) Privileged() bool { return Bool(a.appProperties.Privileged) } -func (a *AndroidApp) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool { +func (a *AndroidApp) IsNativeCoverageNeeded(ctx cc.IsNativeCoverageNeededContext) bool { return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled() } @@ -953,12 +1243,26 @@ func (a *AndroidApp) EnableCoverageIfNeeded() {} var _ cc.Coverage = (*AndroidApp)(nil) +func (a *AndroidApp) IDEInfo(dpInfo *android.IdeInfo) { + a.Library.IDEInfo(dpInfo) + a.aapt.IDEInfo(dpInfo) +} + +func (a *AndroidApp) productCharacteristicsRROPackageName() string { + return proptools.String(a.appProperties.ProductCharacteristicsRROPackageName) +} + +func (a *AndroidApp) productCharacteristicsRROManifestModuleName() string { + return proptools.String(a.appProperties.ProductCharacteristicsRROManifestModuleName) +} + // android_app compiles sources and Android resources into an Android application package `.apk` file. func AndroidAppFactory() android.Module { module := &AndroidApp{} module.Module.dexProperties.Optimize.EnabledByDefault = true module.Module.dexProperties.Optimize.Shrink = proptools.BoolPtr(true) + module.Module.dexProperties.Optimize.Proguard_compatibility = proptools.BoolPtr(false) module.Module.properties.Instrument = true module.Module.properties.Supports_static_instrumentation = true @@ -968,7 +1272,8 @@ func AndroidAppFactory() android.Module { module.AddProperties( &module.aaptProperties, &module.appProperties, - &module.overridableAppProperties) + &module.overridableAppProperties, + &module.Library.sourceProperties) module.usesLibrary.enforce = true @@ -976,11 +1281,72 @@ func AndroidAppFactory() android.Module { android.InitDefaultableModule(module) android.InitOverridableModule(module, &module.overridableAppProperties.Overrides) android.InitApexModule(module) - android.InitBazelModule(module) + + android.AddLoadHook(module, func(ctx android.LoadHookContext) { + a := ctx.Module().(*AndroidApp) + + characteristics := ctx.Config().ProductAAPTCharacteristics() + if characteristics == "default" || characteristics == "" { + module.appProperties.Generate_product_characteristics_rro = nil + // no need to create RRO + return + } + + if !proptools.Bool(module.appProperties.Generate_product_characteristics_rro) { + return + } + + rroPackageName := a.Name() + "__" + strings.ReplaceAll(characteristics, ",", "_") + "__auto_generated_characteristics_rro" + rroManifestName := rroPackageName + "_manifest" + + a.appProperties.ProductCharacteristicsRROPackageName = proptools.StringPtr(rroPackageName) + a.appProperties.ProductCharacteristicsRROManifestModuleName = proptools.StringPtr(rroManifestName) + + rroManifestProperties := struct { + Name *string + Tools []string + Out []string + Srcs []string + Cmd *string + }{ + Name: proptools.StringPtr(rroManifestName), + Tools: []string{"characteristics_rro_generator", "aapt2"}, + Out: []string{"AndroidManifest.xml"}, + Srcs: []string{":" + a.Name() + "{.apk}"}, + Cmd: proptools.StringPtr("$(location characteristics_rro_generator) $$($(location aapt2) dump packagename $(in)) $(out)"), + } + ctx.CreateModule(genrule.GenRuleFactory, &rroManifestProperties) + + rroProperties := struct { + Name *string + Filter_product *string + Aaptflags []string + Manifest *string + Resource_dirs []string + }{ + Name: proptools.StringPtr(rroPackageName), + Filter_product: proptools.StringPtr(characteristics), + Aaptflags: []string{"--auto-add-overlay"}, + Manifest: proptools.StringPtr(":" + rroManifestName), + Resource_dirs: a.aaptProperties.Resource_dirs, + } + if !Bool(a.aaptProperties.Aapt_include_all_resources) { + for _, aaptConfig := range ctx.Config().ProductAAPTConfig() { + rroProperties.Aaptflags = append(rroProperties.Aaptflags, "-c", aaptConfig) + } + } + ctx.CreateModule(RuntimeResourceOverlayFactory, &rroProperties) + }) return module } +// A dictionary of values to be overridden in the manifest. +type Manifest_values struct { + // Overrides the value of package_name in the manifest + ApplicationId *string +} + type appTestProperties struct { // The name of the android_app module that the tests will run against. Instrumentation_for *string @@ -990,6 +1356,8 @@ type appTestProperties struct { // If specified, the mainline module package name in the test config is overwritten by it. Mainline_package_name *string + + Manifest_values Manifest_values } type AndroidTest struct { @@ -1021,6 +1389,7 @@ func (a *AndroidTestHelperApp) includedInTestSuite(searchPrefix string) bool { } func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { + checkMinSdkVersionMts(ctx, a.MinSdkVersion(ctx)) var configs []tradefed.Config if a.appTestProperties.Instrumentation_target_package != nil { a.additionalAaptFlags = append(a.additionalAaptFlags, @@ -1032,6 +1401,13 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.additionalAaptFlags = append(a.additionalAaptFlags, "--rename-instrumentation-target-package "+manifestPackageName) } } + applicationId := a.appTestProperties.Manifest_values.ApplicationId + if applicationId != nil { + if a.overridableAppProperties.Package_name != nil { + ctx.PropertyErrorf("manifest_values.applicationId", "property is not supported when property package_name is set.") + } + a.aapt.manifestValues.applicationId = *applicationId + } a.generateAndroidBuildActions(ctx) for _, module := range a.testProperties.Test_mainline_modules { @@ -1043,6 +1419,22 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.testConfig = a.FixTestConfig(ctx, testConfig) a.extraTestConfigs = android.PathsForModuleSrc(ctx, a.testProperties.Test_options.Extra_test_configs) a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data) + android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{}) + android.SetProvider(ctx, tradefed.BaseTestProviderKey, tradefed.BaseTestProviderData{ + InstalledFiles: a.data, + OutputFile: a.OutputFile(), + TestConfig: a.testConfig, + HostRequiredModuleNames: a.HostRequiredModuleNames(), + TestSuites: a.testProperties.Test_suites, + IsHost: false, + LocalCertificate: a.certificate.AndroidMkString(), + IsUnitTest: Bool(a.testProperties.Test_options.Unit_test), + }) + android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ + TestOnly: true, + TopLevelTarget: true, + }) + } func (a *AndroidTest) FixTestConfig(ctx android.ModuleContext, testConfig android.Path) android.Path { @@ -1119,6 +1511,7 @@ func AndroidTestFactory() android.Module { android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) android.InitOverridableModule(module, &module.overridableAppProperties.Overrides) + return module } @@ -1134,6 +1527,8 @@ type appTestHelperAppProperties struct { // Install the test into a folder named for the module in all test suites. Per_testcase_directory *bool + + Manifest_values Manifest_values } type AndroidTestHelperApp struct { @@ -1176,7 +1571,6 @@ func AndroidTestHelperAppFactory() android.Module { type AndroidAppCertificate struct { android.ModuleBase - android.BazelModuleBase properties AndroidAppCertificateProperties Certificate Certificate @@ -1193,7 +1587,6 @@ func AndroidAppCertificateFactory() android.Module { module := &AndroidAppCertificate{} module.AddProperties(&module.properties) android.InitAndroidModule(module) - android.InitBazelModule(module) return module } @@ -1220,7 +1613,7 @@ func (i *OverrideAndroidApp) GenerateAndroidBuildActions(_ android.ModuleContext func OverrideAndroidAppModuleFactory() android.Module { m := &OverrideAndroidApp{} m.AddProperties( - &OverridableDeviceProperties{}, + &OverridableProperties{}, &overridableAppProperties{}, ) @@ -1234,9 +1627,13 @@ type OverrideAndroidTest struct { android.OverrideModuleBase } -func (i *OverrideAndroidTest) GenerateAndroidBuildActions(_ android.ModuleContext) { +func (i *OverrideAndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { // All the overrides happen in the base module. // TODO(jungjw): Check the base module type. + android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ + TestOnly: true, + TopLevelTarget: true, + }) } // override_android_test is used to create an android_app module based on another android_test by overriding @@ -1284,6 +1681,9 @@ type UsesLibraryProperties struct { // provide the android.test.base statically and use jarjar to rename them so they do not collide // with the classes provided by the android.test.base library. Exclude_uses_libs []string + + // The module names of optional uses-library libraries that are missing from the source tree. + Missing_optional_uses_libs []string `blueprint:"mutated"` } // usesLibrary provides properties and helper functions for AndroidApp and AndroidAppImport to verify that the @@ -1295,22 +1695,16 @@ type usesLibrary struct { // Whether to enforce verify_uses_library check. enforce bool -} -func (u *usesLibrary) addLib(lib string, optional bool) { - if !android.InList(lib, u.usesLibraryProperties.Uses_libs) && !android.InList(lib, u.usesLibraryProperties.Optional_uses_libs) { - if optional { - u.usesLibraryProperties.Optional_uses_libs = append(u.usesLibraryProperties.Optional_uses_libs, lib) - } else { - u.usesLibraryProperties.Uses_libs = append(u.usesLibraryProperties.Uses_libs, lib) - } - } + // Whether dexpreopt should be disabled + shouldDisableDexpreopt bool } func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, addCompatDeps bool) { if !ctx.Config().UnbundledBuild() || ctx.Config().UnbundledBuildImage() { ctx.AddVariationDependencies(nil, usesLibReqTag, u.usesLibraryProperties.Uses_libs...) - ctx.AddVariationDependencies(nil, usesLibOptTag, u.presentOptionalUsesLibs(ctx)...) + presentOptionalUsesLibs := u.presentOptionalUsesLibs(ctx) + ctx.AddVariationDependencies(nil, usesLibOptTag, presentOptionalUsesLibs...) // Only add these extra dependencies if the module is an app that depends on framework // libs. This avoids creating a cyclic dependency: // e.g. framework-res -> org.apache.http.legacy -> ... -> framework-res. @@ -1321,26 +1715,24 @@ func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, addCompatDeps boo ctx.AddVariationDependencies(nil, usesLibCompat28OptTag, dexpreopt.OptionalCompatUsesLibs28...) ctx.AddVariationDependencies(nil, usesLibCompat30OptTag, dexpreopt.OptionalCompatUsesLibs30...) } + _, diff, _ := android.ListSetDifference(u.usesLibraryProperties.Optional_uses_libs, presentOptionalUsesLibs) + u.usesLibraryProperties.Missing_optional_uses_libs = diff } else { ctx.AddVariationDependencies(nil, r8LibraryJarTag, u.usesLibraryProperties.Uses_libs...) ctx.AddVariationDependencies(nil, r8LibraryJarTag, u.presentOptionalUsesLibs(ctx)...) } } -// presentOptionalUsesLibs returns optional_uses_libs after filtering out MissingUsesLibraries, which don't exist in the -// build. +// presentOptionalUsesLibs returns optional_uses_libs after filtering out libraries that don't exist in the source tree. func (u *usesLibrary) presentOptionalUsesLibs(ctx android.BaseModuleContext) []string { - optionalUsesLibs, _ := android.FilterList(u.usesLibraryProperties.Optional_uses_libs, ctx.Config().MissingUsesLibraries()) - return optionalUsesLibs -} - -// Helper function to replace string in a list. -func replaceInList(list []string, oldstr, newstr string) { - for i, str := range list { - if str == oldstr { - list[i] = newstr + optionalUsesLibs := android.FilterListPred(u.usesLibraryProperties.Optional_uses_libs, func(s string) bool { + exists := ctx.OtherModuleExists(s) + if !exists && !android.InList(ctx.ModuleName(), ctx.Config().BuildWarningBadOptionalUsesLibsAllowlist()) { + fmt.Printf("Warning: Module '%s' depends on non-existing optional_uses_libs '%s'\n", ctx.ModuleName(), s) } - } + return exists + }) + return optionalUsesLibs } // Returns a map of module names of shared library dependencies to the paths to their dex jars on @@ -1371,18 +1763,22 @@ func (u *usesLibrary) classLoaderContextForUsesLibDeps(ctx android.ModuleContext } } + // Skip java_sdk_library dependencies that provide stubs, but not an implementation. + // This will be restricted to optional_uses_libs + if sdklib, ok := m.(SdkLibraryDependency); ok { + if tag == usesLibOptTag && sdklib.DexJarBuildPath(ctx).PathOrNil() == nil { + u.shouldDisableDexpreopt = true + return + } + } + if lib, ok := m.(UsesLibraryDependency); ok { libName := dep if ulib, ok := m.(ProvidesUsesLib); ok && ulib.ProvidesUsesLib() != nil { libName = *ulib.ProvidesUsesLib() - // Replace module name with library name in `uses_libs`/`optional_uses_libs` in - // order to pass verify_uses_libraries check (which compares these properties - // against library names written in the manifest). - replaceInList(u.usesLibraryProperties.Uses_libs, dep, libName) - replaceInList(u.usesLibraryProperties.Optional_uses_libs, dep, libName) } clcMap.AddContext(ctx, tag.sdkVersion, libName, tag.optional, - lib.DexJarBuildPath().PathOrNil(), lib.DexJarInstallPath(), + lib.DexJarBuildPath(ctx).PathOrNil(), lib.DexJarInstallPath(), lib.ClassLoaderContexts()) } else if ctx.Config().AllowMissingDependencies() { ctx.AddMissingDependencies([]string{dep}) @@ -1413,7 +1809,7 @@ func (u *usesLibrary) freezeEnforceUsesLibraries() { // an APK with the manifest embedded in it (manifest_check will know which one it is by the file // extension: APKs are supposed to end with '.apk'). func (u *usesLibrary) verifyUsesLibraries(ctx android.ModuleContext, inputFile android.Path, - outputFile android.WritablePath) android.Path { + outputFile android.WritablePath, classLoaderContexts *dexpreopt.ClassLoaderContextMap) android.Path { statusFile := dexpreopt.UsesLibrariesStatusFile(ctx) @@ -1422,7 +1818,7 @@ func (u *usesLibrary) verifyUsesLibraries(ctx android.ModuleContext, inputFile a // non-linux build platforms where dexpreopt is generally disabled (the check may fail due to // various unrelated reasons, such as a failure to get manifest from an APK). global := dexpreopt.GetGlobalConfig(ctx) - if global.DisablePreopt || global.OnlyPreoptBootImageAndSystemServer { + if global.DisablePreopt || global.OnlyPreoptArtBootImage { return inputFile } @@ -1441,140 +1837,37 @@ func (u *usesLibrary) verifyUsesLibraries(ctx android.ModuleContext, inputFile a cmd.Flag("--enforce-uses-libraries-relax") } - for _, lib := range u.usesLibraryProperties.Uses_libs { + requiredUsesLibs, optionalUsesLibs := classLoaderContexts.UsesLibs() + for _, lib := range requiredUsesLibs { cmd.FlagWithArg("--uses-library ", lib) } - - for _, lib := range u.usesLibraryProperties.Optional_uses_libs { + for _, lib := range optionalUsesLibs { cmd.FlagWithArg("--optional-uses-library ", lib) } + // Also add missing optional uses libs, as the manifest check expects them. + // Note that what we add here are the module names of those missing libs, not library names, while + // the manifest check actually expects library names. However, the case where a library is missing + // and the module name != the library name is too rare for us to handle. + for _, lib := range u.usesLibraryProperties.Missing_optional_uses_libs { + cmd.FlagWithArg("--missing-optional-uses-library ", lib) + } + rule.Build("verify_uses_libraries", "verify <uses-library>") return outputFile } // verifyUsesLibrariesManifest checks the <uses-library> tags in an AndroidManifest.xml against // the build system and returns the path to a copy of the manifest. -func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path) android.Path { +func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path, + classLoaderContexts *dexpreopt.ClassLoaderContextMap) android.Path { outputFile := android.PathForModuleOut(ctx, "manifest_check", "AndroidManifest.xml") - return u.verifyUsesLibraries(ctx, manifest, outputFile) + return u.verifyUsesLibraries(ctx, manifest, outputFile, classLoaderContexts) } // verifyUsesLibrariesAPK checks the <uses-library> tags in the manifest of an APK against the build // system and returns the path to a copy of the APK. -func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) android.Path { - u.verifyUsesLibraries(ctx, apk, nil) // for APKs manifest_check does not write output file - outputFile := android.PathForModuleOut(ctx, "verify_uses_libraries", apk.Base()) - return outputFile -} - -// For Bazel / bp2build - -type bazelAndroidAppCertificateAttributes struct { - Certificate string -} - -func (m *AndroidAppCertificate) ConvertWithBp2build(ctx android.TopDownMutatorContext) { - androidAppCertificateBp2Build(ctx, m) -} - -func androidAppCertificateBp2Build(ctx android.TopDownMutatorContext, module *AndroidAppCertificate) { - var certificate string - if module.properties.Certificate != nil { - certificate = *module.properties.Certificate - } - - attrs := &bazelAndroidAppCertificateAttributes{ - Certificate: certificate, - } - - props := bazel.BazelTargetModuleProperties{ - Rule_class: "android_app_certificate", - Bzl_load_location: "//build/bazel/rules/android:rules.bzl", - } - - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs) -} - -type manifestValueAttribute struct { - MinSdkVersion *string -} - -type bazelAndroidAppAttributes struct { - *javaCommonAttributes - *bazelAapt - Deps bazel.LabelListAttribute - Custom_package *string - Certificate bazel.LabelAttribute - Certificate_name bazel.StringAttribute - Manifest_values *manifestValueAttribute -} - -// ConvertWithBp2build is used to convert android_app to Bazel. -func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) { - commonAttrs, bp2BuildInfo := a.convertLibraryAttrsBp2Build(ctx) - depLabels := bp2BuildInfo.DepLabels - - deps := depLabels.Deps - deps.Append(depLabels.StaticDeps) - - aapt := a.convertAaptAttrsWithBp2Build(ctx) - - certificate, certificateName := android.BazelStringOrLabelFromProp(ctx, a.overridableAppProperties.Certificate) - - manifestValues := &manifestValueAttribute{} - // TODO(b/274474008 ): Directly convert deviceProperties.Min_sdk_version in bp2build - // MinSdkVersion(ctx) calls SdkVersion(ctx) if no value for min_sdk_version is set - minSdkVersion := a.MinSdkVersion(ctx) - if !minSdkVersion.IsPreview() && !minSdkVersion.IsInvalid() { - minSdkStr, err := minSdkVersion.EffectiveVersionString(ctx) - if err == nil { - manifestValues.MinSdkVersion = &minSdkStr - } - } - - appAttrs := &bazelAndroidAppAttributes{ - // TODO(b/209576404): handle package name override by product variable PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES - Custom_package: a.overridableAppProperties.Package_name, - Certificate: certificate, - Certificate_name: certificateName, - Manifest_values: manifestValues, - } - - props := bazel.BazelTargetModuleProperties{ - Rule_class: "android_binary", - Bzl_load_location: "//build/bazel/rules/android:rules.bzl", - } - - if !bp2BuildInfo.hasKotlin { - appAttrs.javaCommonAttributes = commonAttrs - appAttrs.bazelAapt = aapt - appAttrs.Deps = deps - } else { - ktName := a.Name() + "_kt" - ctx.CreateBazelTargetModule( - AndroidLibraryBazelTargetModuleProperties(), - android.CommonAttributes{Name: ktName}, - &bazelAndroidLibrary{ - javaLibraryAttributes: &javaLibraryAttributes{ - javaCommonAttributes: commonAttrs, - Deps: deps, - }, - bazelAapt: aapt, - }, - ) - - appAttrs.bazelAapt = &bazelAapt{Manifest: aapt.Manifest} - appAttrs.Deps = bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + ktName}) - appAttrs.javaCommonAttributes = &javaCommonAttributes{ - Sdk_version: commonAttrs.Sdk_version, - } - } - - ctx.CreateBazelTargetModule( - props, - android.CommonAttributes{Name: a.Name()}, - appAttrs, - ) - +func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path, + classLoaderContexts *dexpreopt.ClassLoaderContextMap) { + u.verifyUsesLibraries(ctx, apk, nil, classLoaderContexts) // for APKs manifest_check does not write output file } |