summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/Android.bp7
-rw-r--r--java/OWNERS5
-rw-r--r--java/aar.go72
-rw-r--r--java/android_manifest.go128
-rw-r--r--java/android_resources.go2
-rw-r--r--java/androidmk.go136
-rw-r--r--java/androidmk_test.go46
-rwxr-xr-xjava/app.go408
-rw-r--r--java/app_builder.go22
-rw-r--r--java/app_import.go45
-rw-r--r--java/app_import_test.go296
-rw-r--r--java/app_set.go37
-rw-r--r--java/app_set_test.go22
-rw-r--r--java/app_test.go726
-rw-r--r--java/base.go397
-rw-r--r--java/boot_jars.go7
-rw-r--r--java/bootclasspath.go11
-rw-r--r--java/bootclasspath_fragment.go477
-rw-r--r--java/bootclasspath_fragment_test.go2
-rw-r--r--java/builder.go157
-rw-r--r--java/classpath_fragment.go127
-rw-r--r--java/config/config.go60
-rw-r--r--java/config/error_prone.go24
-rw-r--r--java/config/kotlin.go6
-rw-r--r--java/core-libraries/Android.bp225
-rw-r--r--java/core-libraries/OWNERS3
-rw-r--r--java/device_host_converter.go8
-rw-r--r--java/dex.go92
-rw-r--r--java/dex_test.go103
-rw-r--r--java/dexpreopt.go203
-rw-r--r--java/dexpreopt_bootjars.go136
-rw-r--r--java/dexpreopt_check.go96
-rw-r--r--java/dexpreopt_config.go91
-rw-r--r--java/dexpreopt_test.go232
-rw-r--r--java/droiddoc.go6
-rw-r--r--java/droidstubs.go116
-rw-r--r--java/droidstubs_test.go71
-rw-r--r--java/fuzz.go159
-rw-r--r--java/fuzz_test.go65
-rw-r--r--java/gen.go15
-rw-r--r--java/genrule.go16
-rw-r--r--java/genrule_test.go118
-rw-r--r--java/hiddenapi.go36
-rw-r--r--java/hiddenapi_modular.go257
-rw-r--r--java/hiddenapi_monolithic.go64
-rw-r--r--java/hiddenapi_singleton_test.go3
-rw-r--r--java/jacoco.go2
-rw-r--r--java/jacoco_test.go2
-rw-r--r--java/java.go801
-rw-r--r--java/java_test.go409
-rw-r--r--java/jdeps.go11
-rw-r--r--java/kotlin.go65
-rw-r--r--java/kotlin_test.go137
-rw-r--r--java/legacy_core_platform_api_usage.go23
-rw-r--r--java/lint.go37
-rw-r--r--java/lint_defaults.txt50
-rw-r--r--java/platform_bootclasspath.go93
-rw-r--r--java/platform_compat_config.go6
-rw-r--r--java/plugin.go41
-rw-r--r--java/plugin_test.go5
-rw-r--r--java/prebuilt_apis.go193
-rw-r--r--java/prebuilt_apis_test.go92
-rw-r--r--java/proto.go65
-rw-r--r--java/proto_test.go53
-rw-r--r--java/robolectric.go32
-rw-r--r--java/rro.go29
-rw-r--r--java/rro_test.go86
-rw-r--r--java/sdk.go71
-rw-r--r--java/sdk_library.go557
-rw-r--r--java/sdk_library_test.go318
-rw-r--r--java/sdk_test.go247
-rw-r--r--java/system_modules.go4
-rw-r--r--java/systemserver_classpath_fragment.go228
-rw-r--r--java/systemserver_classpath_fragment_test.go2
-rw-r--r--java/testing.go161
75 files changed, 7294 insertions, 1861 deletions
diff --git a/java/Android.bp b/java/Android.bp
index 59526024a..df0d1eb3d 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -10,10 +10,12 @@ bootstrap_go_package {
"blueprint-pathtools",
"soong",
"soong-android",
+ "soong-bazel",
"soong-cc",
"soong-dexpreopt",
"soong-genrule",
"soong-java-config",
+ "soong-provenance",
"soong-python",
"soong-remoteexec",
"soong-tradefed",
@@ -39,9 +41,11 @@ bootstrap_go_package {
"dex.go",
"dexpreopt.go",
"dexpreopt_bootjars.go",
+ "dexpreopt_check.go",
"dexpreopt_config.go",
"droiddoc.go",
"droidstubs.go",
+ "fuzz.go",
"gen.go",
"genrule.go",
"hiddenapi.go",
@@ -78,6 +82,7 @@ bootstrap_go_package {
"app_test.go",
"bootclasspath_fragment_test.go",
"device_host_converter_test.go",
+ "dex_test.go",
"dexpreopt_test.go",
"dexpreopt_bootjars_test.go",
"droiddoc_test.go",
@@ -91,8 +96,10 @@ bootstrap_go_package {
"platform_bootclasspath_test.go",
"platform_compat_config_test.go",
"plugin_test.go",
+ "prebuilt_apis_test.go",
"rro_test.go",
"sdk_test.go",
+ "sdk_library_test.go",
"system_modules_test.go",
"systemserver_classpath_fragment_test.go",
],
diff --git a/java/OWNERS b/java/OWNERS
index 16ef4d812..5b71b1e35 100644
--- a/java/OWNERS
+++ b/java/OWNERS
@@ -1 +1,4 @@
-per-file dexpreopt*.go = ngeoffray@google.com,calin@google.com,mathieuc@google.com
+per-file dexpreopt*.go = ngeoffray@google.com,calin@google.com,skvadrik@google.com
+
+# For metalava team to disable lint checks in platform
+per-file droidstubs.go = aurimas@google.com,emberrose@google.com,sjgilbert@google.com \ No newline at end of file
diff --git a/java/aar.go b/java/aar.go
index a5cf0fd70..00ff7e774 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -267,18 +267,29 @@ var extractAssetsRule = pctx.AndroidStaticRule("extractAssets",
})
func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkContext,
- classLoaderContexts dexpreopt.ClassLoaderContextMap, extraLinkFlags ...string) {
+ classLoaderContexts dexpreopt.ClassLoaderContextMap, excludedLibs []string,
+ extraLinkFlags ...string) {
transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags :=
aaptLibs(ctx, sdkContext, classLoaderContexts)
+ // Exclude any libraries from the supplied list.
+ classLoaderContexts = classLoaderContexts.ExcludeLibs(excludedLibs)
+
// App manifest file
manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
- manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, classLoaderContexts,
- a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex, a.hasNoCode,
- a.LoggingParent)
+ manifestPath := ManifestFixer(ctx, manifestSrcPath, ManifestFixerParams{
+ SdkContext: sdkContext,
+ ClassLoaderContexts: classLoaderContexts,
+ IsLibrary: a.isLibrary,
+ UseEmbeddedNativeLibs: a.useEmbeddedNativeLibs,
+ UsesNonSdkApis: a.usesNonSdkApis,
+ UseEmbeddedDex: a.useEmbeddedDex,
+ HasNoCode: a.hasNoCode,
+ LoggingParent: a.LoggingParent,
+ })
// Add additional manifest files to transitive manifests.
additionalManifests := android.PathsForModuleSrc(ctx, a.aaptProperties.Additional_manifests)
@@ -514,12 +525,13 @@ func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
if sdkDep.hasFrameworkLibs() {
a.aapt.deps(ctx, sdkDep)
}
+ a.usesLibrary.deps(ctx, sdkDep.hasFrameworkLibs())
}
func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.aapt.isLibrary = true
- a.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap)
- a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts)
+ a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
+ a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts, nil)
a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
@@ -586,16 +598,26 @@ func AndroidLibraryFactory() android.Module {
// AAR (android library) prebuilts
//
+// Properties for android_library_import
type AARImportProperties struct {
+ // ARR (android library prebuilt) filepath. Exactly one ARR is required.
Aars []string `android:"path"`
-
- Sdk_version *string
+ // If not blank, set to the version of the sdk to compile against.
+ // Defaults to private.
+ // Values are of one of the following forms:
+ // 1) numerical API level, "current", "none", or "core_platform"
+ // 2) An SDK kind with an API level: "<sdk kind>_<API level>"
+ // See build/soong/android/sdk_version.go for the complete and up to date list of SDK kinds.
+ // If the SDK kind is empty, it will be set to public
+ Sdk_version *string
+ // If not blank, set the minimum version of the sdk that the compiled artifacts will run against.
+ // Defaults to sdk_version if not set. See sdk_version for possible values.
Min_sdk_version *string
-
+ // List of java static libraries that the included ARR (android library prebuilts) has dependencies to.
Static_libs []string
- Libs []string
-
- // if set to true, run Jetifier against .aar file. Defaults to false.
+ // List of java libraries that the included ARR (android library prebuilts) has dependencies to.
+ Libs []string
+ // If set to true, run Jetifier against .aar file. Defaults to false.
Jetifier *bool
}
@@ -615,6 +637,7 @@ type AARImport struct {
exportPackage android.WritablePath
extraAaptPackagesFile android.WritablePath
manifest android.WritablePath
+ assetsPackage android.WritablePath
exportedStaticPackages android.Paths
@@ -685,9 +708,8 @@ func (a *AARImport) ExportedManifests() android.Paths {
return android.Paths{a.manifest}
}
-// TODO(jungjw): Decide whether we want to implement this.
func (a *AARImport) ExportedAssets() android.OptionalPath {
- return android.OptionalPath{}
+ return android.OptionalPathForPath(a.assetsPackage)
}
// RRO enforcement is not available on aar_import since its RRO dirs are not
@@ -731,10 +753,11 @@ var unzipAAR = pctx.AndroidStaticRule("unzipAAR",
blueprint.RuleParams{
Command: `rm -rf $outDir && mkdir -p $outDir && ` +
`unzip -qoDD -d $outDir $in && rm -rf $outDir/res && touch $out && ` +
+ `${config.Zip2ZipCmd} -i $in -o $assetsPackage 'assets/**/*' && ` +
`${config.MergeZipsCmd} $combinedClassesJar $$(ls $outDir/classes.jar 2> /dev/null) $$(ls $outDir/libs/*.jar 2> /dev/null)`,
- CommandDeps: []string{"${config.MergeZipsCmd}"},
+ CommandDeps: []string{"${config.MergeZipsCmd}", "${config.Zip2ZipCmd}"},
},
- "outDir", "combinedClassesJar")
+ "outDir", "combinedClassesJar", "assetsPackage")
func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if len(a.properties.Aars) != 1 {
@@ -760,15 +783,17 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar")
a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml")
+ a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip")
ctx.Build(pctx, android.BuildParams{
Rule: unzipAAR,
Input: a.aarPath,
- Outputs: android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest},
+ Outputs: android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage},
Description: "unzip AAR",
Args: map[string]string{
"outDir": extractedAARDir.String(),
"combinedClassesJar": a.classpathFile.String(),
+ "assetsPackage": a.assetsPackage.String(),
},
})
@@ -811,6 +836,19 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile,
linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil)
+ // Merge this import's assets with its dependencies' assets (if there are any).
+ if len(transitiveAssets) > 0 {
+ mergedAssets := android.PathForModuleOut(ctx, "merged-assets.zip")
+ inputZips := append(android.Paths{a.assetsPackage}, transitiveAssets...)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: mergeAssetsRule,
+ Inputs: inputZips,
+ Output: mergedAssets,
+ Description: "merge assets from dependencies and self",
+ })
+ a.assetsPackage = mergedAssets
+ }
+
ctx.SetProvider(JavaInfoProvider, JavaInfo{
HeaderJars: android.PathsIfNonNil(a.classpathFile),
ImplementationAndResourcesJars: android.PathsIfNonNil(a.classpathFile),
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 331f941ec..7772b7090 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -16,6 +16,7 @@ package java
import (
"fmt"
+ "strconv"
"strings"
"github.com/google/blueprint"
@@ -27,13 +28,10 @@ import (
var manifestFixerRule = pctx.AndroidStaticRule("manifestFixer",
blueprint.RuleParams{
Command: `${config.ManifestFixerCmd} ` +
- `--minSdkVersion ${minSdkVersion} ` +
- `--targetSdkVersion ${targetSdkVersion} ` +
- `--raise-min-sdk-version ` +
`$args $in $out`,
CommandDeps: []string{"${config.ManifestFixerCmd}"},
},
- "minSdkVersion", "targetSdkVersion", "args")
+ "args")
var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger",
blueprint.RuleParams{
@@ -42,84 +40,124 @@ var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger",
},
"args", "libs")
-// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
-func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext android.SdkContext,
- classLoaderContexts dexpreopt.ClassLoaderContextMap, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis,
- useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path {
+// targetSdkVersion for manifest_fixer
+// When TARGET_BUILD_APPS is not empty, this method returns 10000 for modules targeting an unreleased SDK
+// This enables release builds (that run with TARGET_BUILD_APPS=[val...]) to target APIs that have not yet been finalized as part of an SDK
+func targetSdkVersionForManifestFixer(ctx android.ModuleContext, sdkContext android.SdkContext) string {
+ targetSdkVersionSpec := sdkContext.TargetSdkVersion(ctx)
+ if ctx.Config().UnbundledBuildApps() && targetSdkVersionSpec.ApiLevel.IsPreview() {
+ return strconv.Itoa(android.FutureApiLevel.FinalOrFutureInt())
+ }
+ targetSdkVersion, err := targetSdkVersionSpec.EffectiveVersionString(ctx)
+ if err != nil {
+ ctx.ModuleErrorf("invalid targetSdkVersion: %s", err)
+ }
+ return targetSdkVersion
+}
+
+type ManifestFixerParams struct {
+ SdkContext android.SdkContext
+ ClassLoaderContexts dexpreopt.ClassLoaderContextMap
+ IsLibrary bool
+ UseEmbeddedNativeLibs bool
+ UsesNonSdkApis bool
+ UseEmbeddedDex bool
+ HasNoCode bool
+ TestOnly bool
+ LoggingParent string
+}
+// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
+func ManifestFixer(ctx android.ModuleContext, manifest android.Path,
+ params ManifestFixerParams) android.Path {
var args []string
- if isLibrary {
+
+ if params.IsLibrary {
args = append(args, "--library")
- } else {
- minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersion(ctx)
+ } else if params.SdkContext != nil {
+ minSdkVersion, err := params.SdkContext.MinSdkVersion(ctx).EffectiveVersion(ctx)
if err != nil {
ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
}
if minSdkVersion.FinalOrFutureInt() >= 23 {
- args = append(args, fmt.Sprintf("--extract-native-libs=%v", !useEmbeddedNativeLibs))
- } else if useEmbeddedNativeLibs {
+ args = append(args, fmt.Sprintf("--extract-native-libs=%v", !params.UseEmbeddedNativeLibs))
+ } else if params.UseEmbeddedNativeLibs {
ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it",
minSdkVersion)
}
}
- if usesNonSdkApis {
+ if params.UsesNonSdkApis {
args = append(args, "--uses-non-sdk-api")
}
- if useEmbeddedDex {
+ if params.UseEmbeddedDex {
args = append(args, "--use-embedded-dex")
}
- for _, usesLib := range classLoaderContexts.UsesLibs() {
- if inList(usesLib, dexpreopt.OptionalCompatUsesLibs) {
- args = append(args, "--optional-uses-library", usesLib)
- } else {
+ if params.ClassLoaderContexts != nil {
+ // manifest_fixer should add only the implicit SDK libraries inferred by Soong, not those added
+ // explicitly via `uses_libs`/`optional_uses_libs`.
+ requiredUsesLibs, optionalUsesLibs := params.ClassLoaderContexts.ImplicitUsesLibs()
+
+ for _, usesLib := range requiredUsesLibs {
args = append(args, "--uses-library", usesLib)
}
+ for _, usesLib := range optionalUsesLibs {
+ args = append(args, "--optional-uses-library", usesLib)
+ }
}
- if hasNoCode {
+ if params.HasNoCode {
args = append(args, "--has-no-code")
}
- if loggingParent != "" {
- args = append(args, "--logging-parent", loggingParent)
- }
- var deps android.Paths
- targetSdkVersion, err := sdkContext.TargetSdkVersion(ctx).EffectiveVersionString(ctx)
- if err != nil {
- ctx.ModuleErrorf("invalid targetSdkVersion: %s", err)
- }
- if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
- targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
- deps = append(deps, ApiFingerprintPath(ctx))
+ if params.TestOnly {
+ args = append(args, "--test-only")
}
- minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx)
- if err != nil {
- ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
+ if params.LoggingParent != "" {
+ args = append(args, "--logging-parent", params.LoggingParent)
}
- if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
- minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
- deps = append(deps, ApiFingerprintPath(ctx))
+ var deps android.Paths
+ var argsMapper = make(map[string]string)
+
+ if params.SdkContext != nil {
+ targetSdkVersion := targetSdkVersionForManifestFixer(ctx, params.SdkContext)
+ args = append(args, "--targetSdkVersion ", targetSdkVersion)
+
+ if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
+ targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
+ deps = append(deps, ApiFingerprintPath(ctx))
+ }
+
+ minSdkVersion, err := params.SdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx)
+ if err != nil {
+ ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
+ }
+
+ if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
+ minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
+ deps = append(deps, ApiFingerprintPath(ctx))
+ }
+
+ if err != nil {
+ ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
+ }
+ args = append(args, "--minSdkVersion ", minSdkVersion)
+ args = append(args, "--raise-min-sdk-version")
}
fixedManifest := android.PathForModuleOut(ctx, "manifest_fixer", "AndroidManifest.xml")
- if err != nil {
- ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
- }
+ argsMapper["args"] = strings.Join(args, " ")
+
ctx.Build(pctx, android.BuildParams{
Rule: manifestFixerRule,
Description: "fix manifest",
Input: manifest,
Implicits: deps,
Output: fixedManifest,
- Args: map[string]string{
- "minSdkVersion": minSdkVersion,
- "targetSdkVersion": targetSdkVersion,
- "args": strings.Join(args, " "),
- },
+ Args: argsMapper,
})
return fixedManifest.WithoutRel()
diff --git a/java/android_resources.go b/java/android_resources.go
index 6864ebb90..8c5908f69 100644
--- a/java/android_resources.go
+++ b/java/android_resources.go
@@ -43,7 +43,7 @@ var androidResourceIgnoreFilenames = []string{
// androidResourceGlob returns the list of files in the given directory, using the standard
// exclusion patterns for Android resources.
-func androidResourceGlob(ctx android.ModuleContext, dir android.Path) android.Paths {
+func androidResourceGlob(ctx android.EarlyModuleContext, dir android.Path) android.Paths {
return ctx.GlobFiles(filepath.Join(dir.String(), "**/*"), androidResourceIgnoreFilenames)
}
diff --git a/java/androidmk.go b/java/androidmk.go
index 04357e066..7322637a7 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -29,8 +29,8 @@ func (library *Library) AndroidMkEntriesHostDex() android.AndroidMkEntries {
if hostDexNeeded {
var output android.Path
- if library.dexJarFile != nil {
- output = library.dexJarFile
+ if library.dexJarFile.IsSet() {
+ output = library.dexJarFile.Path()
} else {
output = library.implementationAndResourcesJar
}
@@ -44,9 +44,10 @@ func (library *Library) AndroidMkEntriesHostDex() android.AndroidMkEntries {
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetBool("LOCAL_IS_HOST_MODULE", true)
entries.SetPath("LOCAL_PREBUILT_MODULE_FILE", output)
- if library.dexJarFile != nil {
- entries.SetPath("LOCAL_SOONG_DEX_JAR", library.dexJarFile)
+ if library.dexJarFile.IsSet() {
+ entries.SetPath("LOCAL_SOONG_DEX_JAR", library.dexJarFile.Path())
}
+ entries.SetPath("LOCAL_SOONG_INSTALLED_MODULE", library.hostdexInstallFile)
entries.SetPath("LOCAL_SOONG_HEADER_JAR", library.headerJarFile)
entries.SetPath("LOCAL_SOONG_CLASSES_JAR", library.implementationAndResourcesJar)
entries.SetString("LOCAL_MODULE_STEM", library.Stem()+"-hostdex")
@@ -60,28 +61,23 @@ func (library *Library) AndroidMkEntriesHostDex() android.AndroidMkEntries {
func (library *Library) AndroidMkEntries() []android.AndroidMkEntries {
var entriesList []android.AndroidMkEntries
+ if library.Os() == android.Windows {
+ // Make does not support Windows Java modules
+ return nil
+ }
+
if library.hideApexVariantFromMake {
- // For a java library built for an APEX we don't need Make module
+ // For a java library built for an APEX, we don't need a Make module for itself. Otherwise, it
+ // will conflict with the platform variant because they have the same module name in the
+ // makefile. However, we need to add its dexpreopt outputs as sub-modules, if it is preopted.
+ dexpreoptEntries := library.dexpreopter.AndroidMkEntriesForApex()
+ if len(dexpreoptEntries) > 0 {
+ entriesList = append(entriesList, dexpreoptEntries...)
+ }
entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true})
} else if !library.ApexModuleBase.AvailableFor(android.AvailableToPlatform) {
// Platform variant. If not available for the platform, we don't need Make module.
- // May still need to add some additional dependencies.
- checkedModulePaths := library.additionalCheckedModules
- if len(checkedModulePaths) != 0 {
- entriesList = append(entriesList, android.AndroidMkEntries{
- Class: "FAKE",
- // Need at least one output file in order for this to take effect.
- OutputFile: android.OptionalPathForPath(checkedModulePaths[0]),
- Include: "$(BUILD_PHONY_PACKAGE)",
- ExtraEntries: []android.AndroidMkExtraEntriesFunc{
- func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", checkedModulePaths.Strings()...)
- },
- },
- })
- } else {
- entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true})
- }
+ entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true})
} else {
entriesList = append(entriesList, android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
@@ -100,8 +96,8 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries {
if library.installFile == nil {
entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", true)
}
- if library.dexJarFile != nil {
- entries.SetPath("LOCAL_SOONG_DEX_JAR", library.dexJarFile)
+ if library.dexJarFile.IsSet() {
+ entries.SetPath("LOCAL_SOONG_DEX_JAR", library.dexJarFile.Path())
}
if len(library.dexpreopter.builtInstalled) > 0 {
entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", library.dexpreopter.builtInstalled)
@@ -114,11 +110,8 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries {
entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoReportClassesFile)
}
- entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.classLoaderContexts.UsesLibs()...)
-
- if len(library.additionalCheckedModules) != 0 {
- entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...)
- }
+ requiredUsesLibs, optionalUsesLibs := library.classLoaderContexts.UsesLibs()
+ entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", append(requiredUsesLibs, optionalUsesLibs...)...)
entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_DICT", library.dexer.proguardDictionary)
entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", library.dexer.proguardUsageZip)
@@ -140,20 +133,21 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries {
}
// Called for modules that are a component of a test suite.
-func testSuiteComponent(entries *android.AndroidMkEntries, test_suites []string) {
+func testSuiteComponent(entries *android.AndroidMkEntries, test_suites []string, perTestcaseDirectory bool) {
entries.SetString("LOCAL_MODULE_TAGS", "tests")
if len(test_suites) > 0 {
entries.AddCompatibilityTestSuites(test_suites...)
} else {
entries.AddCompatibilityTestSuites("null-suite")
}
+ entries.SetBoolIfTrue("LOCAL_COMPATIBILITY_PER_TESTCASE_DIRECTORY", perTestcaseDirectory)
}
func (j *Test) AndroidMkEntries() []android.AndroidMkEntries {
entriesList := j.Library.AndroidMkEntries()
entries := &entriesList[0]
entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- testSuiteComponent(entries, j.testProperties.Test_suites)
+ testSuiteComponent(entries, j.testProperties.Test_suites, Bool(j.testProperties.Per_testcase_directory))
if j.testConfig != nil {
entries.SetPath("LOCAL_FULL_TEST_CONFIG", j.testConfig)
}
@@ -181,14 +175,21 @@ func (j *TestHelperLibrary) AndroidMkEntries() []android.AndroidMkEntries {
entriesList := j.Library.AndroidMkEntries()
entries := &entriesList[0]
entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- testSuiteComponent(entries, j.testHelperLibraryProperties.Test_suites)
+ testSuiteComponent(entries, j.testHelperLibraryProperties.Test_suites, Bool(j.testHelperLibraryProperties.Per_testcase_directory))
})
return entriesList
}
func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries {
- if prebuilt.hideApexVariantFromMake || !prebuilt.ContainingSdk().Unversioned() {
+ if prebuilt.hideApexVariantFromMake {
+ // For a library imported from a prebuilt APEX, we don't need a Make module for itself, as we
+ // don't need to install it. However, we need to add its dexpreopt outputs as sub-modules, if it
+ // is preopted.
+ dexpreoptEntries := prebuilt.dexpreopter.AndroidMkEntriesForApex()
+ return append(dexpreoptEntries, android.AndroidMkEntries{Disabled: true})
+ }
+ if !prebuilt.ContainingSdk().Unversioned() {
return []android.AndroidMkEntries{android.AndroidMkEntries{
Disabled: true,
}}
@@ -200,8 +201,8 @@ func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries {
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !Bool(prebuilt.properties.Installable))
- if prebuilt.dexJarFile != nil {
- entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile)
+ if prebuilt.dexJarFile.IsSet() {
+ entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile.Path())
}
entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile)
entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile)
@@ -220,12 +221,12 @@ func (prebuilt *DexImport) AndroidMkEntries() []android.AndroidMkEntries {
}
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
- OutputFile: android.OptionalPathForPath(prebuilt.dexJarFile),
+ OutputFile: android.OptionalPathForPath(prebuilt.dexJarFile.Path()),
Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- if prebuilt.dexJarFile != nil {
- entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile)
+ if prebuilt.dexJarFile.IsSet() {
+ entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile.Path())
}
if len(prebuilt.dexpreopter.builtInstalled) > 0 {
entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", prebuilt.dexpreopter.builtInstalled)
@@ -262,6 +263,10 @@ func (prebuilt *AARImport) AndroidMkEntries() []android.AndroidMkEntries {
}
func (binary *Binary) AndroidMkEntries() []android.AndroidMkEntries {
+ if binary.Os() == android.Windows {
+ // Make does not support Windows Java modules
+ return nil
+ }
if !binary.isWrapperVariant {
return []android.AndroidMkEntries{android.AndroidMkEntries{
@@ -272,8 +277,8 @@ func (binary *Binary) AndroidMkEntries() []android.AndroidMkEntries {
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetPath("LOCAL_SOONG_HEADER_JAR", binary.headerJarFile)
entries.SetPath("LOCAL_SOONG_CLASSES_JAR", binary.implementationAndResourcesJar)
- if binary.dexJarFile != nil {
- entries.SetPath("LOCAL_SOONG_DEX_JAR", binary.dexJarFile)
+ if binary.dexJarFile.IsSet() {
+ entries.SetPath("LOCAL_SOONG_DEX_JAR", binary.dexJarFile.Path())
}
if len(binary.dexpreopter.builtInstalled) > 0 {
entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", binary.dexpreopter.builtInstalled)
@@ -288,11 +293,6 @@ func (binary *Binary) AndroidMkEntries() []android.AndroidMkEntries {
}}
} else {
outputFile := binary.wrapperFile
- // Have Make installation trigger Soong installation by using Soong's install path as
- // the output file.
- if binary.Host() {
- outputFile = binary.binaryFile
- }
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "EXECUTABLES",
@@ -314,7 +314,7 @@ func (binary *Binary) AndroidMkEntries() []android.AndroidMkEntries {
}
func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries {
- if app.hideApexVariantFromMake || app.appProperties.HideFromMake {
+ if app.hideApexVariantFromMake || app.IsHideFromMake() {
return []android.AndroidMkEntries{android.AndroidMkEntries{
Disabled: true,
}}
@@ -329,8 +329,8 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries {
entries.SetString("LOCAL_MODULE", app.installApkName)
entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", app.appProperties.PreventInstall)
entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", app.exportPackage)
- if app.dexJarFile != nil {
- entries.SetPath("LOCAL_SOONG_DEX_JAR", app.dexJarFile)
+ if app.dexJarFile.IsSet() {
+ entries.SetPath("LOCAL_SOONG_DEX_JAR", app.dexJarFile.Path())
}
if app.implementationAndResourcesJar != nil {
entries.SetPath("LOCAL_SOONG_CLASSES_JAR", app.implementationAndResourcesJar)
@@ -411,30 +411,24 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries {
},
ExtraFooters: []android.AndroidMkExtraFootersFunc{
func(w io.Writer, name, prefix, moduleDir string) {
- if app.noticeOutputs.Merged.Valid() {
- fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
- app.installApkName, app.noticeOutputs.Merged.String(), app.installApkName+"_NOTICE")
- }
- if app.noticeOutputs.TxtOutput.Valid() {
- fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
- app.installApkName, app.noticeOutputs.TxtOutput.String(), app.installApkName+"_NOTICE.txt")
- }
- if app.noticeOutputs.HtmlOutput.Valid() {
- fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
- app.installApkName, app.noticeOutputs.HtmlOutput.String(), app.installApkName+"_NOTICE.html")
+ if app.javaApiUsedByOutputFile.String() != "" {
+ fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s/$(notdir %s))\n",
+ app.installApkName, app.javaApiUsedByOutputFile.String(), "java_apis_used_by_apex", app.javaApiUsedByOutputFile.String())
}
},
- },
- }}
+ }},
+ }
}
func (a *AndroidApp) getOverriddenPackages() []string {
var overridden []string
- if len(a.appProperties.Overrides) > 0 {
- overridden = append(overridden, a.appProperties.Overrides...)
+ if len(a.overridableAppProperties.Overrides) > 0 {
+ overridden = append(overridden, a.overridableAppProperties.Overrides...)
}
- if a.Name() != a.installApkName {
- overridden = append(overridden, a.Name())
+ // When APK name is overridden via PRODUCT_PACKAGE_NAME_OVERRIDES
+ // ensure that the original name is overridden.
+ if a.Stem() != a.installApkName {
+ overridden = append(overridden, a.Stem())
}
return overridden
}
@@ -443,7 +437,7 @@ func (a *AndroidTest) AndroidMkEntries() []android.AndroidMkEntries {
entriesList := a.AndroidApp.AndroidMkEntries()
entries := &entriesList[0]
entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- testSuiteComponent(entries, a.testProperties.Test_suites)
+ testSuiteComponent(entries, a.testProperties.Test_suites, Bool(a.testProperties.Per_testcase_directory))
if a.testConfig != nil {
entries.SetPath("LOCAL_FULL_TEST_CONFIG", a.testConfig)
}
@@ -459,7 +453,7 @@ func (a *AndroidTestHelperApp) AndroidMkEntries() []android.AndroidMkEntries {
entriesList := a.AndroidApp.AndroidMkEntries()
entries := &entriesList[0]
entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- testSuiteComponent(entries, a.appTestHelperAppProperties.Test_suites)
+ testSuiteComponent(entries, a.appTestHelperAppProperties.Test_suites, Bool(a.appTestHelperAppProperties.Per_testcase_directory))
// introduce a flag variable to control the generation of the .config file
entries.SetString("LOCAL_DISABLE_TEST_CONFIG", "true")
})
@@ -670,7 +664,7 @@ func (a *AndroidTestImport) AndroidMkEntries() []android.AndroidMkEntries {
entriesList := a.AndroidAppImport.AndroidMkEntries()
entries := &entriesList[0]
entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- testSuiteComponent(entries, a.testProperties.Test_suites)
+ testSuiteComponent(entries, a.testProperties.Test_suites, Bool(a.testProperties.Per_testcase_directory))
androidMkWriteTestData(a.data, entries)
})
return entriesList
@@ -692,7 +686,7 @@ func (r *RuntimeResourceOverlay) AndroidMkEntries() []android.AndroidMkEntries {
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_CERTIFICATE", r.certificate.AndroidMkString())
- entries.SetPath("LOCAL_MODULE_PATH", r.installDir.ToMakePath())
+ entries.SetPath("LOCAL_MODULE_PATH", r.installDir)
entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", r.properties.Overrides...)
},
},
@@ -703,12 +697,12 @@ func (apkSet *AndroidAppSet) AndroidMkEntries() []android.AndroidMkEntries {
return []android.AndroidMkEntries{
android.AndroidMkEntries{
Class: "APPS",
- OutputFile: android.OptionalPathForPath(apkSet.packedOutput),
+ OutputFile: android.OptionalPathForPath(apkSet.primaryOutput),
Include: "$(BUILD_SYSTEM)/soong_android_app_set.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", apkSet.Privileged())
- entries.SetString("LOCAL_APK_SET_INSTALL_FILE", apkSet.InstallFile())
+ entries.SetPath("LOCAL_APK_SET_INSTALL_FILE", apkSet.PackedAdditionalOutputs())
entries.SetPath("LOCAL_APKCERTS_FILE", apkSet.apkcertsFile)
entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", apkSet.properties.Overrides...)
},
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
index 246c0eb07..197da4f38 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -206,3 +206,49 @@ func TestAndroidTestHelperApp_LocalDisableTestConfig(t *testing.T) {
t.Errorf("Unexpected flag value - expected: %q, actual: %q", expected, actual)
}
}
+
+func TestGetOverriddenPackages(t *testing.T) {
+ ctx, _ := testJava(
+ t, `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ overrides: ["qux"]
+ }
+
+ override_android_app {
+ name: "foo_override",
+ base: "foo",
+ overrides: ["bar"]
+ }
+ `)
+
+ expectedVariants := []struct {
+ name string
+ moduleName string
+ variantName string
+ overrides []string
+ }{
+ {
+ name: "foo",
+ moduleName: "foo",
+ variantName: "android_common",
+ overrides: []string{"qux"},
+ },
+ {
+ name: "foo",
+ moduleName: "foo_override",
+ variantName: "android_common_foo_override",
+ overrides: []string{"bar", "foo"},
+ },
+ }
+
+ for _, expected := range expectedVariants {
+ mod := ctx.ModuleForTests(expected.name, expected.variantName).Module()
+ entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
+ actual := entries.EntryMap["LOCAL_OVERRIDES_PACKAGES"]
+
+ android.AssertDeepEquals(t, "overrides property", expected.overrides, actual)
+ }
+}
diff --git a/java/app.go b/java/app.go
index fc1ace07b..94e6fb950 100755
--- a/java/app.go
+++ b/java/app.go
@@ -19,13 +19,13 @@ package java
import (
"path/filepath"
- "sort"
"strings"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/bazel"
"android/soong/cc"
"android/soong/dexpreopt"
"android/soong/tradefed"
@@ -63,13 +63,6 @@ type appProperties struct {
// list of resource labels to generate individual resource packages
Package_splits []string
- // Names of modules to be overridden. Listed modules can only be other binaries
- // (in Make or Soong).
- // This does not completely prevent installation of the overridden binaries, but if both
- // binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
- // from PRODUCT_PACKAGES.
- Overrides []string
-
// list of native libraries that will be provided in or alongside the resulting jar
Jni_libs []string `android:"arch_variant"`
@@ -106,7 +99,6 @@ type appProperties struct {
// cc.Coverage related properties
PreventInstall bool `blueprint:"mutated"`
- HideFromMake bool `blueprint:"mutated"`
IsCoverageVariant bool `blueprint:"mutated"`
// Whether this app is considered mainline updatable or not. When set to true, this will enforce
@@ -125,6 +117,9 @@ type overridableAppProperties struct {
// Name of the signing certificate lineage file or filegroup module.
Lineage *string `android:"path"`
+ // For overriding the --rotation-min-sdk-version property of apksig
+ RotationMinSdkVersion *string
+
// the package name of this app. The package name in the manifest file is used if one was not given.
Package_name *string
@@ -133,9 +128,17 @@ type overridableAppProperties struct {
// Whether to rename the package in resources to the override name rather than the base name. Defaults to true.
Rename_resources_package *bool
+
+ // Names of modules to be overridden. Listed modules can only be other binaries
+ // (in Make or Soong).
+ // This does not completely prevent installation of the overridden binaries, but if both
+ // binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
+ // from PRODUCT_PACKAGES.
+ Overrides []string
}
type AndroidApp struct {
+ android.BazelModuleBase
Library
aapt
android.OverridableModuleBase
@@ -162,11 +165,11 @@ type AndroidApp struct {
additionalAaptFlags []string
- noticeOutputs android.NoticeOutputs
-
overriddenManifestPackageName string
android.ApexBundleDepsInfo
+
+ javaApiUsedByOutputFile android.ModuleOutPath
}
func (a *AndroidApp) IsInstallable() bool {
@@ -275,6 +278,7 @@ func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleCon
func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.checkAppSdkVersions(ctx)
a.generateAndroidBuildActions(ctx)
+ a.generateJavaUsedByApex(ctx)
}
func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
@@ -288,7 +292,7 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
if minSdkVersion, err := a.MinSdkVersion(ctx).EffectiveVersion(ctx); err == nil {
a.checkJniLibsSdkVersion(ctx, minSdkVersion)
- android.CheckMinSdkVersion(a, ctx, minSdkVersion)
+ android.CheckMinSdkVersion(ctx, minSdkVersion, a.WalkPayloadDeps)
} else {
ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
}
@@ -300,10 +304,6 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
// 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).
-// b/155209650: until min_sdk_version is properly supported, use sdk_version instead.
-// because, sdk_version is overridden by min_sdk_version (if set as smaller)
-// and sdkLinkType is checked with dependencies so we can be sure that the whole dependency tree
-// will meet the requirements.
func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion android.ApiLevel) {
// It's enough to check direct JNI deps' sdk_version because all transitive deps from JNI deps are checked in cc.checkLinkType()
ctx.VisitDirectDeps(func(m android.Module) {
@@ -314,10 +314,10 @@ func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVer
// The domain of cc.sdk_version is "current" and <number>
// We can rely on android.SdkSpec to convert it to <number> so that "current" is
// handled properly regardless of sdk finalization.
- jniSdkVersion, err := android.SdkSpecFrom(ctx, dep.SdkVersion()).EffectiveVersion(ctx)
+ jniSdkVersion, err := android.SdkSpecFrom(ctx, dep.MinSdkVersion()).EffectiveVersion(ctx)
if err != nil || minSdkVersion.LessThan(jniSdkVersion) {
- ctx.OtherModuleErrorf(dep, "sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)",
- dep.SdkVersion(), minSdkVersion, ctx.ModuleName())
+ ctx.OtherModuleErrorf(dep, "min_sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)",
+ dep.MinSdkVersion(), minSdkVersion, ctx.ModuleName())
return
}
@@ -423,7 +423,8 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
a.aapt.splitNames = a.appProperties.Package_splits
a.aapt.LoggingParent = String(a.overridableAppProperties.Logging_parent)
- a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts, aaptLinkFlags...)
+ a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts,
+ a.usesLibraryProperties.Exclude_uses_libs, aaptLinkFlags...)
// apps manifests are handled by aapt, don't let Module see them
a.properties.Manifest = nil
@@ -468,12 +469,13 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
a.dexpreopter.classLoaderContexts = a.classLoaderContexts
a.dexpreopter.manifestFile = a.mergedManifestFile
+ a.dexpreopter.preventInstall = a.appProperties.PreventInstall
if ctx.ModuleName() != "framework-res" {
a.Module.compile(ctx, a.aaptSrcJar)
}
- return a.dexJarFile
+ return a.dexJarFile.PathOrNil()
}
func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext) android.WritablePath {
@@ -482,7 +484,7 @@ func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext
a.jniLibs = jniLibs
if a.shouldEmbedJnis(ctx) {
jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
- a.installPathForJNISymbols = a.installPath(ctx).ToMakePath()
+ a.installPathForJNISymbols = a.installPath(ctx)
TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.useEmbeddedNativeLibs(ctx))
for _, jni := range jniLibs {
if jni.coverageFile.Valid() {
@@ -519,53 +521,6 @@ func (a *AndroidApp) JNISymbolsInstalls(installPath string) android.RuleBuilderI
return jniSymbols
}
-func (a *AndroidApp) noticeBuildActions(ctx android.ModuleContext) {
- // Collect NOTICE files from all dependencies.
- seenModules := make(map[android.Module]bool)
- noticePathSet := make(map[android.Path]bool)
-
- ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
- // Have we already seen this?
- if _, ok := seenModules[child]; ok {
- return false
- }
- seenModules[child] = true
-
- // Skip host modules.
- if child.Target().Os.Class == android.Host {
- return false
- }
-
- paths := child.(android.Module).NoticeFiles()
- if len(paths) > 0 {
- for _, path := range paths {
- noticePathSet[path] = true
- }
- }
- return true
- })
-
- // If the app has one, add it too.
- if len(a.NoticeFiles()) > 0 {
- for _, path := range a.NoticeFiles() {
- noticePathSet[path] = true
- }
- }
-
- if len(noticePathSet) == 0 {
- return
- }
- var noticePaths []android.Path
- for path := range noticePathSet {
- noticePaths = append(noticePaths, path)
- }
- sort.Slice(noticePaths, func(i, j int) bool {
- return noticePaths[i].String() < noticePaths[j].String()
- })
-
- a.noticeOutputs = android.BuildNoticeOutput(ctx, a.installDir, a.installApkName+".apk", noticePaths)
-}
-
// Reads and prepends a main cert from the default cert dir if it hasn't been set already, i.e. it
// isn't a cert module reference. Also checks and enforces system cert restriction if applicable.
func processMainCert(m android.ModuleBase, certPropValue string, certificates []Certificate, ctx android.ModuleContext) []Certificate {
@@ -618,7 +573,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
// Check if the install APK name needs to be overridden.
- a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(a.Name())
+ a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(a.Stem())
if ctx.ModuleName() == "framework-res" {
// framework-res.apk is installed as system/framework/framework-res.apk
@@ -632,11 +587,6 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
}
a.onDeviceDir = android.InstallPathToOnDevicePath(ctx, a.installDir)
- a.noticeBuildActions(ctx)
- if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
- a.aapt.noticeFile = a.noticeOutputs.HtmlGzOutput
- }
-
a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
// Process all building blocks, from AAPT to certificates.
@@ -646,8 +596,12 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
a.usesLibrary.freezeEnforceUsesLibraries()
// Add implicit SDK libraries to <uses-library> list.
- for _, usesLib := range a.classLoaderContexts.UsesLibs() {
- a.usesLibrary.addLib(usesLib, inList(usesLib, dexpreopt.OptionalCompatUsesLibs))
+ 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.
@@ -673,7 +627,21 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
}
certificates := processMainCert(a.ModuleBase, a.getCertString(ctx), certificateDeps, ctx)
- a.certificate = certificates[0]
+
+ // This can be reached with an empty certificate list if AllowMissingDependencies is set
+ // and the certificate property for this module is a module reference to a missing module.
+ if len(certificates) > 0 {
+ a.certificate = certificates[0]
+ } else {
+ if !ctx.Config().AllowMissingDependencies() && len(ctx.GetMissingDependencies()) > 0 {
+ panic("Should only get here if AllowMissingDependencies set and there are missing dependencies")
+ }
+ // Set a certificate to avoid panics later when accessing it.
+ a.certificate = Certificate{
+ Key: android.PathForModuleOut(ctx, "missing.pk8"),
+ Pem: android.PathForModuleOut(ctx, "missing.pem"),
+ }
+ }
// Build a final signed app package.
packageFile := android.PathForModuleOut(ctx, a.installApkName+".apk")
@@ -686,19 +654,40 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
if lineage := String(a.overridableAppProperties.Lineage); lineage != "" {
lineageFile = android.PathForModuleSrc(ctx, lineage)
}
- CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile)
+
+ rotationMinSdkVersion := String(a.overridableAppProperties.RotationMinSdkVersion)
+
+ CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion)
a.outputFile = packageFile
if v4SigningRequested {
a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
}
+ if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
+ noticeFile := android.PathForModuleOut(ctx, "NOTICE.html.gz")
+ android.BuildNoticeHtmlOutputFromLicenseMetadata(
+ ctx, noticeFile, "", "",
+ []string{
+ a.installDir.String() + "/",
+ android.PathForModuleInstall(ctx).String() + "/",
+ a.outputFile.String(),
+ })
+ noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
+ builder := android.NewRuleBuilder(pctx, ctx)
+ builder.Command().Text("cp").
+ Input(noticeFile).
+ Output(noticeAssetPath)
+ builder.Build("notice_dir", "Building notice dir")
+ a.aapt.noticeFile = android.OptionalPathForPath(noticeAssetPath)
+ }
+
for _, split := range a.aapt.splits {
// Sign the split APKs
packageFile := android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk")
if v4SigningRequested {
v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk.idsig")
}
- CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile)
+ 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)
@@ -713,11 +702,15 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
// Install the app package.
- if (Bool(a.Module.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() {
- ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile)
+ if (Bool(a.Module.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() &&
+ !a.appProperties.PreventInstall {
+
+ var extraInstalledPaths android.Paths
for _, extra := range a.extraOutputFiles {
- ctx.InstallFile(a.installDir, extra.Base(), extra)
+ installed := ctx.InstallFile(a.installDir, extra.Base(), extra)
+ extraInstalledPaths = append(extraInstalledPaths, installed)
}
+ ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...)
}
a.buildAppDependencyInfo(ctx)
@@ -753,18 +746,18 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface,
}
lib := dep.OutputFile()
- path := lib.Path()
- if seenModulePaths[path.String()] {
- return false
- }
- seenModulePaths[path.String()] = true
+ if lib.Valid() {
+ path := lib.Path()
+ if seenModulePaths[path.String()] {
+ return false
+ }
+ seenModulePaths[path.String()] = true
- if checkNativeSdkVersion && dep.SdkVersion() == "" {
- ctx.PropertyErrorf("jni_libs", "JNI dependency %q uses platform APIs, but this module does not",
- otherName)
- }
+ if checkNativeSdkVersion && dep.SdkVersion() == "" {
+ ctx.PropertyErrorf("jni_libs", "JNI dependency %q uses platform APIs, but this module does not",
+ otherName)
+ }
- if lib.Valid() {
jniLibs = append(jniLibs, jniLib{
name: ctx.OtherModuleName(module),
path: path,
@@ -859,6 +852,10 @@ func (a *AndroidApp) Updatable() bool {
return Bool(a.appProperties.Updatable)
}
+func (a *AndroidApp) SetUpdatable(val bool) {
+ a.appProperties.Updatable = &val
+}
+
func (a *AndroidApp) getCertString(ctx android.BaseModuleContext) string {
certificate, overridden := ctx.DeviceConfig().OverrideCertificateFor(ctx.ModuleName())
if overridden {
@@ -897,10 +894,6 @@ func (a *AndroidApp) SetPreventInstall() {
a.appProperties.PreventInstall = true
}
-func (a *AndroidApp) HideFromMake() {
- a.appProperties.HideFromMake = true
-}
-
func (a *AndroidApp) MarkAsCoverageVariant(coverage bool) {
a.appProperties.IsCoverageVariant = coverage
}
@@ -917,6 +910,7 @@ func AndroidAppFactory() android.Module {
module.Module.dexProperties.Optimize.Shrink = proptools.BoolPtr(true)
module.Module.properties.Instrument = true
+ module.Module.properties.Supports_static_instrumentation = true
module.Module.properties.Installable = proptools.BoolPtr(true)
module.addHostAndDeviceProperties()
@@ -929,8 +923,9 @@ func AndroidAppFactory() android.Module {
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
- android.InitOverridableModule(module, &module.appProperties.Overrides)
+ android.InitOverridableModule(module, &module.overridableAppProperties.Overrides)
android.InitApexModule(module)
+ android.InitBazelModule(module)
return module
}
@@ -994,6 +989,7 @@ func (a *AndroidTest) FixTestConfig(ctx android.ModuleContext, testConfig androi
command := rule.Command().BuiltTool("test_config_fixer").Input(testConfig).Output(fixedConfig)
fixNeeded := false
+ // Auto-generated test config uses `ModuleName` as the APK name. So fix it if it is not the case.
if ctx.ModuleName() != a.installApkName {
fixNeeded = true
command.FlagWithArg("--test-file-name ", a.installApkName+".apk")
@@ -1034,6 +1030,7 @@ func AndroidTestFactory() android.Module {
module.Module.dexProperties.Optimize.EnabledByDefault = true
module.Module.properties.Instrument = true
+ module.Module.properties.Supports_static_instrumentation = true
module.Module.properties.Installable = proptools.BoolPtr(true)
module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
module.appProperties.AlwaysPackageNativeLibs = true
@@ -1050,7 +1047,7 @@ func AndroidTestFactory() android.Module {
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
- android.InitOverridableModule(module, &module.appProperties.Overrides)
+ android.InitOverridableModule(module, &module.overridableAppProperties.Overrides)
return module
}
@@ -1063,6 +1060,9 @@ type appTestHelperAppProperties struct {
// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
// explicitly.
Auto_gen_config *bool
+
+ // Install the test into a folder named for the module in all test suites.
+ Per_testcase_directory *bool
}
type AndroidTestHelperApp struct {
@@ -1104,6 +1104,8 @@ func AndroidTestHelperAppFactory() android.Module {
type AndroidAppCertificate struct {
android.ModuleBase
+ android.BazelModuleBase
+
properties AndroidAppCertificateProperties
Certificate Certificate
}
@@ -1119,6 +1121,7 @@ func AndroidAppCertificateFactory() android.Module {
module := &AndroidAppCertificate{}
module.AddProperties(&module.properties)
android.InitAndroidModule(module)
+ android.InitBazelModule(module)
return module
}
@@ -1144,7 +1147,10 @@ func (i *OverrideAndroidApp) GenerateAndroidBuildActions(_ android.ModuleContext
// some of its properties.
func OverrideAndroidAppModuleFactory() android.Module {
m := &OverrideAndroidApp{}
- m.AddProperties(&overridableAppProperties{})
+ m.AddProperties(
+ &OverridableDeviceProperties{},
+ &overridableAppProperties{},
+ )
android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon)
android.InitOverrideModule(m)
@@ -1189,6 +1195,23 @@ type UsesLibraryProperties struct {
// libraries, because SDK ones are automatically picked up by Soong. The <uses-library> name
// normally is the same as the module name, but there are exceptions.
Provides_uses_lib *string
+
+ // A list of shared library names to exclude from the classpath of the APK. Adding a library here
+ // will prevent it from being used when precompiling the APK and prevent it from being implicitly
+ // added to the APK's manifest's <uses-library> elements.
+ //
+ // Care must be taken when using this as it could result in runtime errors if the APK actually
+ // uses classes provided by the library and which are not provided in any other way.
+ //
+ // This is primarily intended for use by various CTS tests that check the runtime handling of the
+ // android.test.base shared library (and related libraries) but which depend on some common
+ // libraries that depend on the android.test.base library. Without this those tests will end up
+ // with a <uses-library android:name="android.test.base"/> in their manifest which would either
+ // render the tests worthless (as they would be testing the wrong behavior), or would break the
+ // test altogether by providing access to classes that the tests were not expecting. Those tests
+ // 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
}
// usesLibrary provides properties and helper functions for AndroidApp and AndroidAppImport to verify that the
@@ -1213,18 +1236,29 @@ func (u *usesLibrary) addLib(lib string, optional bool) {
}
func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, hasFrameworkLibs bool) {
- if !ctx.Config().UnbundledBuild() {
- ctx.AddVariationDependencies(nil, usesLibTag, u.usesLibraryProperties.Uses_libs...)
- ctx.AddVariationDependencies(nil, usesLibTag, u.presentOptionalUsesLibs(ctx)...)
+ if !ctx.Config().UnbundledBuild() || ctx.Config().UnbundledBuildImage() {
+ reqTag := makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false, false)
+ ctx.AddVariationDependencies(nil, reqTag, u.usesLibraryProperties.Uses_libs...)
+
+ optTag := makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, true, false)
+ ctx.AddVariationDependencies(nil, optTag, u.presentOptionalUsesLibs(ctx)...)
+
// Only add these extra dependencies if the module depends on framework libs. This avoids
// creating a cyclic dependency:
// e.g. framework-res -> org.apache.http.legacy -> ... -> framework-res.
if hasFrameworkLibs {
- // Dexpreopt needs paths to the dex jars of these libraries in order to construct
- // class loader context for dex2oat. Add them as a dependency with a special tag.
- ctx.AddVariationDependencies(nil, usesLibCompat29Tag, dexpreopt.CompatUsesLibs29...)
- ctx.AddVariationDependencies(nil, usesLibCompat28Tag, dexpreopt.OptionalCompatUsesLibs28...)
- ctx.AddVariationDependencies(nil, usesLibCompat30Tag, dexpreopt.OptionalCompatUsesLibs30...)
+ // Add implicit <uses-library> dependencies on compatibility libraries. Some of them are
+ // optional, and some required --- this depends on the most common usage of the library
+ // and may be wrong for some apps (they need explicit `uses_libs`/`optional_uses_libs`).
+
+ compat28OptTag := makeUsesLibraryDependencyTag(28, true, true)
+ ctx.AddVariationDependencies(nil, compat28OptTag, dexpreopt.OptionalCompatUsesLibs28...)
+
+ compat29ReqTag := makeUsesLibraryDependencyTag(29, false, true)
+ ctx.AddVariationDependencies(nil, compat29ReqTag, dexpreopt.CompatUsesLibs29...)
+
+ compat30OptTag := makeUsesLibraryDependencyTag(30, true, true)
+ ctx.AddVariationDependencies(nil, compat30OptTag, dexpreopt.OptionalCompatUsesLibs30...)
}
}
}
@@ -1245,36 +1279,53 @@ func replaceInList(list []string, oldstr, newstr string) {
}
}
-// Returns a map of module names of shared library dependencies to the paths
-// to their dex jars on host and on device.
+// Returns a map of module names of shared library dependencies to the paths to their dex jars on
+// host and on device.
func (u *usesLibrary) classLoaderContextForUsesLibDeps(ctx android.ModuleContext) dexpreopt.ClassLoaderContextMap {
clcMap := make(dexpreopt.ClassLoaderContextMap)
- if !ctx.Config().UnbundledBuild() {
- ctx.VisitDirectDeps(func(m android.Module) {
- if tag, ok := ctx.OtherModuleDependencyTag(m).(usesLibraryDependencyTag); ok {
- dep := ctx.OtherModuleName(m)
- 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,
- lib.DexJarBuildPath(), lib.DexJarInstallPath(), lib.ClassLoaderContexts())
- } else if ctx.Config().AllowMissingDependencies() {
- ctx.AddMissingDependencies([]string{dep})
- } else {
- ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be a java library", dep)
- }
- }
- })
+ // Skip when UnbundledBuild() is true, but UnbundledBuildImage() is false. With
+ // UnbundledBuildImage() it is necessary to generate dexpreopt.config for post-dexpreopting.
+ if ctx.Config().UnbundledBuild() && !ctx.Config().UnbundledBuildImage() {
+ return clcMap
}
+ ctx.VisitDirectDeps(func(m android.Module) {
+ tag, isUsesLibTag := ctx.OtherModuleDependencyTag(m).(usesLibraryDependencyTag)
+ if !isUsesLibTag {
+ return
+ }
+
+ dep := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(m))
+
+ // Skip stub libraries. A dependency on the implementation library has been added earlier,
+ // so it will be added to CLC, but the stub shouldn't be. Stub libraries can be distingushed
+ // from implementation libraries by their name, which is different as it has a suffix.
+ if comp, ok := m.(SdkLibraryComponentDependency); ok {
+ if impl := comp.OptionalSdkLibraryImplementation(); impl != nil && *impl != dep {
+ 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, tag.implicit,
+ lib.DexJarBuildPath().PathOrNil(), lib.DexJarInstallPath(),
+ lib.ClassLoaderContexts())
+ } else if ctx.Config().AllowMissingDependencies() {
+ ctx.AddMissingDependencies([]string{dep})
+ } else {
+ ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be a java library", dep)
+ }
+ })
return clcMap
}
@@ -1352,3 +1403,94 @@ func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk andr
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:android_app_certificate.bzl",
+ }
+
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
+}
+
+type bazelAndroidAppAttributes struct {
+ *javaCommonAttributes
+ Deps bazel.LabelListAttribute
+ Manifest bazel.Label
+ Custom_package *string
+ Resource_files bazel.LabelListAttribute
+ Certificate *bazel.Label
+ Certificate_name *string
+}
+
+// ConvertWithBp2build is used to convert android_app to Bazel.
+func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ commonAttrs, depLabels := a.convertLibraryAttrsBp2Build(ctx)
+
+ deps := depLabels.Deps
+ if !commonAttrs.Srcs.IsEmpty() {
+ deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them
+ } else if !deps.IsEmpty() || !depLabels.StaticDeps.IsEmpty() {
+ ctx.ModuleErrorf("android_app has dynamic or static dependencies but no sources." +
+ " Bazel does not allow direct dependencies without sources nor exported" +
+ " dependencies on android_binary rule.")
+ }
+
+ manifest := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
+
+ resourceFiles := bazel.LabelList{
+ Includes: []bazel.Label{},
+ }
+ for _, dir := range android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res") {
+ files := android.RootToModuleRelativePaths(ctx, androidResourceGlob(ctx, dir))
+ resourceFiles.Includes = append(resourceFiles.Includes, files...)
+ }
+
+ var certificate *bazel.Label
+ certificateNamePtr := a.overridableAppProperties.Certificate
+ certificateName := proptools.StringDefault(certificateNamePtr, "")
+ certModule := android.SrcIsModule(certificateName)
+ if certModule != "" {
+ c := android.BazelLabelForModuleDepSingle(ctx, certificateName)
+ certificate = &c
+ certificateNamePtr = nil
+ }
+
+ attrs := &bazelAndroidAppAttributes{
+ commonAttrs,
+ deps,
+ android.BazelLabelForModuleSrcSingle(ctx, manifest),
+ // TODO(b/209576404): handle package name override by product variable PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES
+ a.overridableAppProperties.Package_name,
+ bazel.MakeLabelListAttribute(resourceFiles),
+ certificate,
+ certificateNamePtr,
+ }
+
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "android_binary",
+ Bzl_load_location: "//build/bazel/rules/android:android_binary.bzl",
+ }
+
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: a.Name()}, attrs)
+
+}
diff --git a/java/app_builder.go b/java/app_builder.go
index 4a18dcada..31023cb9c 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -52,7 +52,7 @@ var combineApk = pctx.AndroidStaticRule("combineApk",
})
func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
- packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path) {
+ packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path, rotationMinSdkVersion string) {
unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk"
unsignedApk := android.PathForModuleOut(ctx, unsignedApkName)
@@ -73,10 +73,10 @@ func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.Writa
Implicits: deps,
})
- SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile, lineageFile)
+ SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile, lineageFile, rotationMinSdkVersion)
}
-func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate, v4SignatureFile android.WritablePath, lineageFile android.Path) {
+func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate, v4SignatureFile android.WritablePath, lineageFile android.Path, rotationMinSdkVersion string) {
var certificateArgs []string
var deps android.Paths
@@ -97,6 +97,10 @@ func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, u
deps = append(deps, lineageFile)
}
+ if rotationMinSdkVersion != "" {
+ flags = append(flags, "--rotation-min-sdk-version", rotationMinSdkVersion)
+ }
+
rule := Signapk
args := map[string]string{
"certificates": strings.Join(certificateArgs, " "),
@@ -254,6 +258,18 @@ func TransformJniLibsToJar(ctx android.ModuleContext, outputFile android.Writabl
})
}
+func (a *AndroidApp) generateJavaUsedByApex(ctx android.ModuleContext) {
+ javaApiUsedByOutputFile := android.PathForModuleOut(ctx, a.installApkName+"_using.xml")
+ javaUsedByRule := android.NewRuleBuilder(pctx, ctx)
+ javaUsedByRule.Command().
+ Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")).
+ BuiltTool("dexdeps").
+ Output(javaApiUsedByOutputFile).
+ Input(a.Library.Module.outputFile)
+ javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex")
+ a.javaApiUsedByOutputFile = javaApiUsedByOutputFile
+}
+
func targetToJniDir(target android.Target) string {
return filepath.Join("lib", target.Arch.Abi[0])
}
diff --git a/java/app_import.go b/java/app_import.go
index 3371e8e1f..58c01a447 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -22,6 +22,7 @@ import (
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/provenance"
)
func init() {
@@ -57,11 +58,13 @@ type AndroidAppImport struct {
installPath android.InstallPath
hideApexVariantFromMake bool
+
+ provenanceMetaDataFile android.OutputPath
}
type AndroidAppImportProperties struct {
// A prebuilt apk to import
- Apk *string
+ Apk *string `android:"path"`
// The name of a certificate in the default certificate directory or an android_app_certificate
// module name in the form ":module". Should be empty if presigned or default_dev_cert is set.
@@ -77,6 +80,9 @@ type AndroidAppImportProperties struct {
// Name of the signing certificate lineage file or filegroup module.
Lineage *string `android:"path"`
+ // For overriding the --rotation-min-sdk-version property of apksig
+ RotationMinSdkVersion *string
+
// Sign with the default system dev certificate. Must be used judiciously. Most imported apps
// need to either specify a specific certificate or be presigned.
Default_dev_cert *bool
@@ -99,6 +105,9 @@ type AndroidAppImportProperties struct {
// If set, create package-export.apk, which other packages can
// use to get PRODUCT-agnostic resource data like IDs and type definitions.
Export_package_resources *bool
+
+ // Optional. Install to a subdirectory of the default install path for the module
+ Relative_install_path *string
}
func (a *AndroidAppImport) IsInstallable() bool {
@@ -201,9 +210,9 @@ func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool {
return false
}
- // Uncompress dex in APKs of privileged apps
- if ctx.Config().UncompressPrivAppDex() && a.Privileged() {
- return true
+ // Uncompress dex in APKs of priv-apps if and only if DONT_UNCOMPRESS_PRIV_APPS_DEXS is false.
+ if a.Privileged() {
+ return ctx.Config().UncompressPrivAppDex()
}
return shouldUncompressDex(ctx, &a.dexpreopter)
@@ -263,20 +272,25 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext
jnisUncompressed := android.PathForModuleOut(ctx, "jnis-uncompressed", ctx.ModuleName()+".apk")
a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath)
- var installDir android.InstallPath
+ var pathFragments []string
+ relInstallPath := String(a.properties.Relative_install_path)
if a.isPrebuiltFrameworkRes() {
// framework-res.apk is installed as system/framework/framework-res.apk
- installDir = android.PathForModuleInstall(ctx, "framework")
+ if relInstallPath != "" {
+ ctx.PropertyErrorf("relative_install_path", "Relative_install_path cannot be set for framework-res")
+ }
+ pathFragments = []string{"framework"}
a.preprocessed = true
} else if Bool(a.properties.Privileged) {
- installDir = android.PathForModuleInstall(ctx, "priv-app", a.BaseModuleName())
+ pathFragments = []string{"priv-app", relInstallPath, a.BaseModuleName()}
} else if ctx.InstallInTestcases() {
- installDir = android.PathForModuleInstall(ctx, a.BaseModuleName(), ctx.DeviceConfig().DeviceArch())
+ pathFragments = []string{relInstallPath, a.BaseModuleName(), ctx.DeviceConfig().DeviceArch()}
} else {
- installDir = android.PathForModuleInstall(ctx, "app", a.BaseModuleName())
+ pathFragments = []string{"app", relInstallPath, a.BaseModuleName()}
}
+ installDir := android.PathForModuleInstall(ctx, pathFragments...)
a.dexpreopter.isApp = true
a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk")
a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
@@ -322,7 +336,10 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext
if lineage := String(a.properties.Lineage); lineage != "" {
lineageFile = android.PathForModuleSrc(ctx, lineage)
}
- SignAppPackage(ctx, signed, jnisUncompressed, certificates, nil, lineageFile)
+
+ rotationMinSdkVersion := String(a.properties.RotationMinSdkVersion)
+
+ SignAppPackage(ctx, signed, jnisUncompressed, certificates, nil, lineageFile, rotationMinSdkVersion)
a.outputFile = signed
} else {
alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename)
@@ -335,6 +352,8 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext
if apexInfo.IsForPlatform() {
a.installPath = ctx.InstallFile(installDir, apkFilename, a.outputFile)
+ artifactPath := android.PathForModuleSrc(ctx, *a.properties.Apk)
+ a.provenanceMetaDataFile = provenance.GenerateArtifactProvenanceMetaData(ctx, artifactPath, a.installPath)
}
// TODO: androidmk converter jni libs
@@ -360,6 +379,10 @@ func (a *AndroidAppImport) Certificate() Certificate {
return a.certificate
}
+func (a *AndroidAppImport) ProvenanceMetaDataFile() android.OutputPath {
+ return a.provenanceMetaDataFile
+}
+
var dpiVariantGroupType reflect.Type
var archVariantGroupType reflect.Type
var supportedDpis = []string{"ldpi", "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"}
@@ -449,7 +472,7 @@ func createVariantGroupType(variants []string, variantGroupName string) reflect.
// apk: "prebuilts/example_xhdpi.apk",
// },
// },
-// certificate: "PRESIGNED",
+// presigned: true,
// }
func AndroidAppImportFactory() android.Module {
module := &AndroidAppImport{}
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 147ae45bb..41be092e2 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -15,6 +15,7 @@
package java
import (
+ "fmt"
"reflect"
"regexp"
"strings"
@@ -52,6 +53,11 @@ func TestAndroidAppImport(t *testing.T) {
if expected != signingFlag {
t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
}
+ rule := variant.Rule("genProvenanceMetaData")
+ android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String())
+ android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String())
+ android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"])
+ android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"])
}
func TestAndroidAppImport_NoDexPreopt(t *testing.T) {
@@ -73,6 +79,12 @@ func TestAndroidAppImport_NoDexPreopt(t *testing.T) {
variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule != nil {
t.Errorf("dexpreopt shouldn't have run.")
}
+
+ rule := variant.Rule("genProvenanceMetaData")
+ android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String())
+ android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String())
+ android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"])
+ android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"])
}
func TestAndroidAppImport_Presigned(t *testing.T) {
@@ -101,6 +113,12 @@ func TestAndroidAppImport_Presigned(t *testing.T) {
if variant.MaybeOutput("zip-aligned/foo.apk").Rule == nil {
t.Errorf("can't find aligning rule")
}
+
+ rule := variant.Rule("genProvenanceMetaData")
+ android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String())
+ android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String())
+ android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"])
+ android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"])
}
func TestAndroidAppImport_SigningLineage(t *testing.T) {
@@ -111,6 +129,7 @@ func TestAndroidAppImport_SigningLineage(t *testing.T) {
certificate: "platform",
additional_certificates: [":additional_certificate"],
lineage: "lineage.bin",
+ rotationMinSdkVersion: "32",
}
android_app_certificate {
@@ -130,12 +149,19 @@ func TestAndroidAppImport_SigningLineage(t *testing.T) {
if expected != certificatesFlag {
t.Errorf("Incorrect certificates flags, expected: %q, got: %q", expected, certificatesFlag)
}
- // Check cert signing lineage flag.
- signingFlag := signedApk.Args["flags"]
- expected = "--lineage lineage.bin"
- if expected != signingFlag {
- t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
+
+ // Check cert signing flags.
+ actualCertSigningFlags := signedApk.Args["flags"]
+ expectedCertSigningFlags := "--lineage lineage.bin --rotation-min-sdk-version 32"
+ if expectedCertSigningFlags != actualCertSigningFlags {
+ t.Errorf("Incorrect signing flags, expected: %q, got: %q", expectedCertSigningFlags, actualCertSigningFlags)
}
+
+ rule := variant.Rule("genProvenanceMetaData")
+ android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String())
+ android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String())
+ android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"])
+ android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"])
}
func TestAndroidAppImport_SigningLineageFilegroup(t *testing.T) {
@@ -162,6 +188,12 @@ func TestAndroidAppImport_SigningLineageFilegroup(t *testing.T) {
if expected != signingFlag {
t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
}
+
+ rule := variant.Rule("genProvenanceMetaData")
+ android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String())
+ android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String())
+ android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"])
+ android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"])
}
func TestAndroidAppImport_DefaultDevCert(t *testing.T) {
@@ -191,6 +223,12 @@ func TestAndroidAppImport_DefaultDevCert(t *testing.T) {
if expected != signingFlag {
t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
}
+
+ rule := variant.Rule("genProvenanceMetaData")
+ android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String())
+ android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String())
+ android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"])
+ android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"])
}
func TestAndroidAppImport_DpiVariants(t *testing.T) {
@@ -213,40 +251,46 @@ func TestAndroidAppImport_DpiVariants(t *testing.T) {
}
`
testCases := []struct {
- name string
- aaptPreferredConfig *string
- aaptPrebuiltDPI []string
- expected string
+ name string
+ aaptPreferredConfig *string
+ aaptPrebuiltDPI []string
+ expected string
+ expectedProvenanceMetaDataArtifactPath string
}{
{
- name: "no preferred",
- aaptPreferredConfig: nil,
- aaptPrebuiltDPI: []string{},
- expected: "verify_uses_libraries/apk/app.apk",
+ name: "no preferred",
+ aaptPreferredConfig: nil,
+ aaptPrebuiltDPI: []string{},
+ expected: "verify_uses_libraries/apk/app.apk",
+ expectedProvenanceMetaDataArtifactPath: "prebuilts/apk/app.apk",
},
{
- name: "AAPTPreferredConfig matches",
- aaptPreferredConfig: proptools.StringPtr("xhdpi"),
- aaptPrebuiltDPI: []string{"xxhdpi", "ldpi"},
- expected: "verify_uses_libraries/apk/app_xhdpi.apk",
+ name: "AAPTPreferredConfig matches",
+ aaptPreferredConfig: proptools.StringPtr("xhdpi"),
+ aaptPrebuiltDPI: []string{"xxhdpi", "ldpi"},
+ expected: "verify_uses_libraries/apk/app_xhdpi.apk",
+ expectedProvenanceMetaDataArtifactPath: "prebuilts/apk/app_xhdpi.apk",
},
{
- name: "AAPTPrebuiltDPI matches",
- aaptPreferredConfig: proptools.StringPtr("mdpi"),
- aaptPrebuiltDPI: []string{"xxhdpi", "xhdpi"},
- expected: "verify_uses_libraries/apk/app_xxhdpi.apk",
+ name: "AAPTPrebuiltDPI matches",
+ aaptPreferredConfig: proptools.StringPtr("mdpi"),
+ aaptPrebuiltDPI: []string{"xxhdpi", "xhdpi"},
+ expected: "verify_uses_libraries/apk/app_xxhdpi.apk",
+ expectedProvenanceMetaDataArtifactPath: "prebuilts/apk/app_xxhdpi.apk",
},
{
- name: "non-first AAPTPrebuiltDPI matches",
- aaptPreferredConfig: proptools.StringPtr("mdpi"),
- aaptPrebuiltDPI: []string{"ldpi", "xhdpi"},
- expected: "verify_uses_libraries/apk/app_xhdpi.apk",
+ name: "non-first AAPTPrebuiltDPI matches",
+ aaptPreferredConfig: proptools.StringPtr("mdpi"),
+ aaptPrebuiltDPI: []string{"ldpi", "xhdpi"},
+ expected: "verify_uses_libraries/apk/app_xhdpi.apk",
+ expectedProvenanceMetaDataArtifactPath: "prebuilts/apk/app_xhdpi.apk",
},
{
- name: "no matches",
- aaptPreferredConfig: proptools.StringPtr("mdpi"),
- aaptPrebuiltDPI: []string{"ldpi", "xxxhdpi"},
- expected: "verify_uses_libraries/apk/app.apk",
+ name: "no matches",
+ aaptPreferredConfig: proptools.StringPtr("mdpi"),
+ aaptPrebuiltDPI: []string{"ldpi", "xxxhdpi"},
+ expected: "verify_uses_libraries/apk/app.apk",
+ expectedProvenanceMetaDataArtifactPath: "prebuilts/apk/app.apk",
},
}
@@ -269,6 +313,12 @@ func TestAndroidAppImport_DpiVariants(t *testing.T) {
if strings.HasSuffix(matches[1], test.expected) {
t.Errorf("wrong src apk, expected: %q got: %q", test.expected, matches[1])
}
+
+ provenanceMetaDataRule := variant.Rule("genProvenanceMetaData")
+ android.AssertStringEquals(t, "Invalid input", test.expectedProvenanceMetaDataArtifactPath, provenanceMetaDataRule.Inputs[0].String())
+ android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", provenanceMetaDataRule.Output.String())
+ android.AssertStringEquals(t, "Invalid args", "foo", provenanceMetaDataRule.Args["module_name"])
+ android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", provenanceMetaDataRule.Args["install_path"])
}
}
@@ -289,16 +339,25 @@ func TestAndroidAppImport_Filename(t *testing.T) {
`)
testCases := []struct {
- name string
- expected string
+ name string
+ expected string
+ onDevice string
+ expectedArtifactPath string
+ expectedMetaDataPath string
}{
{
- name: "foo",
- expected: "foo.apk",
+ name: "foo",
+ expected: "foo.apk",
+ onDevice: "/system/app/foo/foo.apk",
+ expectedArtifactPath: "prebuilts/apk/app.apk",
+ expectedMetaDataPath: "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto",
},
{
- name: "bar",
- expected: "bar_sample.apk",
+ name: "bar",
+ expected: "bar_sample.apk",
+ onDevice: "/system/app/bar/bar_sample.apk",
+ expectedArtifactPath: "prebuilts/apk/app.apk",
+ expectedMetaDataPath: "out/soong/.intermediates/provenance_metadata/bar/provenance_metadata.textproto",
},
}
@@ -315,15 +374,23 @@ func TestAndroidAppImport_Filename(t *testing.T) {
t.Errorf("Incorrect LOCAL_INSTALLED_MODULE_STEM value '%s', expected '%s'",
actualValues, expectedValues)
}
+ rule := variant.Rule("genProvenanceMetaData")
+ android.AssertStringEquals(t, "Invalid input", test.expectedArtifactPath, rule.Inputs[0].String())
+ android.AssertStringEquals(t, "Invalid output", test.expectedMetaDataPath, rule.Output.String())
+ android.AssertStringEquals(t, "Invalid args", test.name, rule.Args["module_name"])
+ android.AssertStringEquals(t, "Invalid args", test.onDevice, rule.Args["install_path"])
}
}
func TestAndroidAppImport_ArchVariants(t *testing.T) {
// The test config's target arch is ARM64.
testCases := []struct {
- name string
- bp string
- expected string
+ name string
+ bp string
+ expected string
+ artifactPath string
+ metaDataPath string
+ installPath string
}{
{
name: "matching arch",
@@ -342,7 +409,9 @@ func TestAndroidAppImport_ArchVariants(t *testing.T) {
},
}
`,
- expected: "verify_uses_libraries/apk/app_arm64.apk",
+ expected: "verify_uses_libraries/apk/app_arm64.apk",
+ artifactPath: "prebuilts/apk/app_arm64.apk",
+ installPath: "/system/app/foo/foo.apk",
},
{
name: "no matching arch",
@@ -361,7 +430,9 @@ func TestAndroidAppImport_ArchVariants(t *testing.T) {
},
}
`,
- expected: "verify_uses_libraries/apk/app.apk",
+ expected: "verify_uses_libraries/apk/app.apk",
+ artifactPath: "prebuilts/apk/app.apk",
+ installPath: "/system/app/foo/foo.apk",
},
{
name: "no matching arch without default",
@@ -379,7 +450,9 @@ func TestAndroidAppImport_ArchVariants(t *testing.T) {
},
}
`,
- expected: "",
+ expected: "",
+ artifactPath: "prebuilts/apk/app_arm.apk",
+ installPath: "/system/app/foo/foo.apk",
},
}
@@ -392,6 +465,8 @@ func TestAndroidAppImport_ArchVariants(t *testing.T) {
if variant.Module().Enabled() {
t.Error("module should have been disabled, but wasn't")
}
+ rule := variant.MaybeRule("genProvenanceMetaData")
+ android.AssertDeepEquals(t, "Provenance metadata is not empty", android.TestingBuildParams{}, rule)
continue
}
jniRuleCommand := variant.Output("jnis-uncompressed/foo.apk").RuleParams.Command
@@ -402,6 +477,11 @@ func TestAndroidAppImport_ArchVariants(t *testing.T) {
if strings.HasSuffix(matches[1], test.expected) {
t.Errorf("wrong src apk, expected: %q got: %q", test.expected, matches[1])
}
+ rule := variant.Rule("genProvenanceMetaData")
+ android.AssertStringEquals(t, "Invalid input", test.artifactPath, rule.Inputs[0].String())
+ android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String())
+ android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"])
+ android.AssertStringEquals(t, "Invalid args", test.installPath, rule.Args["install_path"])
}
}
@@ -493,6 +573,69 @@ func TestAndroidAppImport_frameworkRes(t *testing.T) {
}
}
+func TestAndroidAppImport_relativeInstallPath(t *testing.T) {
+ bp := `
+ android_app_import {
+ name: "no_relative_install_path",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ }
+
+ android_app_import {
+ name: "relative_install_path",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ relative_install_path: "my/path",
+ }
+
+ android_app_import {
+ name: "framework-res",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ prefer: true,
+ }
+
+ android_app_import {
+ name: "privileged_relative_install_path",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ privileged: true,
+ relative_install_path: "my/path"
+ }
+ `
+ testCases := []struct {
+ name string
+ expectedInstallPath string
+ errorMessage string
+ }{
+ {
+ name: "no_relative_install_path",
+ expectedInstallPath: "out/soong/target/product/test_device/system/app/no_relative_install_path/no_relative_install_path.apk",
+ errorMessage: "Install path is not correct when relative_install_path is missing",
+ },
+ {
+ name: "relative_install_path",
+ expectedInstallPath: "out/soong/target/product/test_device/system/app/my/path/relative_install_path/relative_install_path.apk",
+ errorMessage: "Install path is not correct for app when relative_install_path is present",
+ },
+ {
+ name: "prebuilt_framework-res",
+ expectedInstallPath: "out/soong/target/product/test_device/system/framework/framework-res.apk",
+ errorMessage: "Install path is not correct for framework-res",
+ },
+ {
+ name: "privileged_relative_install_path",
+ expectedInstallPath: "out/soong/target/product/test_device/system/priv-app/my/path/privileged_relative_install_path/privileged_relative_install_path.apk",
+ errorMessage: "Install path is not correct for privileged app when relative_install_path is present",
+ },
+ }
+ for _, testCase := range testCases {
+ ctx, _ := testJava(t, bp)
+ mod := ctx.ModuleForTests(testCase.name, "android_common").Module().(*AndroidAppImport)
+ android.AssertPathRelativeToTopEquals(t, testCase.errorMessage, testCase.expectedInstallPath, mod.installPath)
+ }
+}
+
func TestAndroidTestImport(t *testing.T) {
ctx, _ := testJava(t, `
android_test_import {
@@ -593,3 +736,74 @@ func TestAndroidTestImport_Preprocessed(t *testing.T) {
}
}
}
+
+func TestAndroidTestImport_UncompressDex(t *testing.T) {
+ testCases := []struct {
+ name string
+ bp string
+ }{
+ {
+ name: "normal",
+ bp: `
+ android_app_import {
+ name: "foo",
+ presigned: true,
+ apk: "prebuilts/apk/app.apk",
+ }
+ `,
+ },
+ {
+ name: "privileged",
+ bp: `
+ android_app_import {
+ name: "foo",
+ presigned: true,
+ privileged: true,
+ apk: "prebuilts/apk/app.apk",
+ }
+ `,
+ },
+ }
+
+ test := func(t *testing.T, bp string, unbundled bool, dontUncompressPrivAppDexs bool) {
+ t.Helper()
+
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ if unbundled {
+ variables.Unbundled_build = proptools.BoolPtr(true)
+ }
+ variables.UncompressPrivAppDex = proptools.BoolPtr(!dontUncompressPrivAppDexs)
+ }),
+ ).RunTestWithBp(t, bp)
+
+ foo := result.ModuleForTests("foo", "android_common")
+ actual := foo.MaybeRule("uncompress-dex").Rule != nil
+
+ expect := !unbundled
+ if strings.Contains(bp, "privileged: true") {
+ if dontUncompressPrivAppDexs {
+ expect = false
+ } else {
+ // TODO(b/194504107): shouldn't priv-apps be always uncompressed unless
+ // DONT_UNCOMPRESS_PRIV_APPS_DEXS is true (regardless of unbundling)?
+ // expect = true
+ }
+ }
+
+ android.AssertBoolEquals(t, "uncompress dex", expect, actual)
+ }
+
+ for _, unbundled := range []bool{false, true} {
+ for _, dontUncompressPrivAppDexs := range []bool{false, true} {
+ for _, tt := range testCases {
+ name := fmt.Sprintf("%s,unbundled:%t,dontUncompressPrivAppDexs:%t",
+ tt.name, unbundled, dontUncompressPrivAppDexs)
+ t.Run(name, func(t *testing.T) {
+ test(t, tt.bp, unbundled, dontUncompressPrivAppDexs)
+ })
+ }
+ }
+ }
+}
diff --git a/java/app_set.go b/java/app_set.go
index 6b25638da..694b1670e 100644
--- a/java/app_set.go
+++ b/java/app_set.go
@@ -55,10 +55,10 @@ type AndroidAppSet struct {
android.DefaultableModuleBase
prebuilt android.Prebuilt
- properties AndroidAppSetProperties
- packedOutput android.WritablePath
- installFile string
- apkcertsFile android.ModuleOutPath
+ properties AndroidAppSetProperties
+ packedOutput android.WritablePath
+ primaryOutput android.WritablePath
+ apkcertsFile android.ModuleOutPath
}
func (as *AndroidAppSet) Name() string {
@@ -78,11 +78,11 @@ func (as *AndroidAppSet) Privileged() bool {
}
func (as *AndroidAppSet) OutputFile() android.Path {
- return as.packedOutput
+ return as.primaryOutput
}
-func (as *AndroidAppSet) InstallFile() string {
- return as.installFile
+func (as *AndroidAppSet) PackedAdditionalOutputs() android.Path {
+ return as.packedOutput
}
func (as *AndroidAppSet) APKCertsFile() android.Path {
@@ -114,11 +114,11 @@ func SupportedAbis(ctx android.ModuleContext) []string {
func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
as.packedOutput = android.PathForModuleOut(ctx, ctx.ModuleName()+".zip")
+ as.primaryOutput = android.PathForModuleOut(ctx, as.BaseModuleName()+".apk")
as.apkcertsFile = android.PathForModuleOut(ctx, "apkcerts.txt")
// We are assuming here that the install file in the APK
// set has `.apk` suffix. If it doesn't the build will fail.
// APK sets containing APEX files are handled elsewhere.
- as.installFile = as.BaseModuleName() + ".apk"
screenDensities := "all"
if dpis := ctx.Config().ProductAAPTPrebuiltDPI(); len(dpis) > 0 {
screenDensities = strings.ToUpper(strings.Join(dpis, ","))
@@ -127,11 +127,11 @@ func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext)
// TODO(asmundak): do we support device features
ctx.Build(pctx,
android.BuildParams{
- Rule: extractMatchingApks,
- Description: "Extract APKs from APK set",
- Output: as.packedOutput,
- ImplicitOutput: as.apkcertsFile,
- Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)},
+ Rule: extractMatchingApks,
+ Description: "Extract APKs from APK set",
+ Output: as.primaryOutput,
+ ImplicitOutputs: android.WritablePaths{as.packedOutput, as.apkcertsFile},
+ Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)},
Args: map[string]string{
"abis": strings.Join(SupportedAbis(ctx), ","),
"allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)),
@@ -140,10 +140,21 @@ func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext)
"stem": as.BaseModuleName(),
"apkcerts": as.apkcertsFile.String(),
"partition": as.PartitionTag(ctx.DeviceConfig()),
+ "zip": as.packedOutput.String(),
},
})
+
+ var installDir android.InstallPath
+ if as.Privileged() {
+ installDir = android.PathForModuleInstall(ctx, "priv-app", as.BaseModuleName())
+ } else {
+ installDir = android.PathForModuleInstall(ctx, "app", as.BaseModuleName())
+ }
+ ctx.InstallFileWithExtraFilesZip(installDir, as.BaseModuleName()+".apk", as.primaryOutput, as.packedOutput)
}
+func (as *AndroidAppSet) InstallBypassMake() bool { return true }
+
// android_app_set extracts a set of APKs based on the target device
// configuration and installs this set as "split APKs".
// The extracted set always contains an APK whose name is
diff --git a/java/app_set_test.go b/java/app_set_test.go
index adaf71bab..03eb66786 100644
--- a/java/app_set_test.go
+++ b/java/app_set_test.go
@@ -17,19 +17,20 @@ package java
import (
"fmt"
"reflect"
+ "strings"
"testing"
"android/soong/android"
)
func TestAndroidAppSet(t *testing.T) {
- ctx, _ := testJava(t, `
+ result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
android_app_set {
name: "foo",
set: "prebuilts/apks/app.apks",
prerelease: true,
}`)
- module := ctx.ModuleForTests("foo", "android_common")
+ module := result.ModuleForTests("foo", "android_common")
const packedSplitApks = "foo.zip"
params := module.Output(packedSplitApks)
if params.Rule == nil {
@@ -41,9 +42,22 @@ func TestAndroidAppSet(t *testing.T) {
if s := params.Args["partition"]; s != "system" {
t.Errorf("wrong partition value: '%s', expected 'system'", s)
}
- mkEntries := android.AndroidMkEntriesForTest(t, ctx, module.Module())[0]
+
+ android.AssertPathRelativeToTopEquals(t, "incorrect output path",
+ "out/soong/.intermediates/foo/android_common/foo.apk", params.Output)
+
+ android.AssertPathsRelativeToTopEquals(t, "incorrect implicit output paths",
+ []string{
+ "out/soong/.intermediates/foo/android_common/foo.zip",
+ "out/soong/.intermediates/foo/android_common/apkcerts.txt",
+ },
+ params.ImplicitOutputs.Paths())
+
+ mkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, module.Module())[0]
actualInstallFile := mkEntries.EntryMap["LOCAL_APK_SET_INSTALL_FILE"]
- expectedInstallFile := []string{"foo.apk"}
+ expectedInstallFile := []string{
+ strings.Replace(params.ImplicitOutputs[0].String(), android.OutSoongDir, result.Config.SoongOutDir(), 1),
+ }
if !reflect.DeepEqual(actualInstallFile, expectedInstallFile) {
t.Errorf("Unexpected LOCAL_APK_SET_INSTALL_FILE value: '%s', expected: '%s',",
actualInstallFile, expectedInstallFile)
diff --git a/java/app_test.go b/java/app_test.go
index a99ac62da..8e331d46e 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -27,7 +27,6 @@ import (
"android/soong/android"
"android/soong/cc"
"android/soong/dexpreopt"
- "android/soong/genrule"
)
// testApp runs tests using the prepareForJavaTest
@@ -144,14 +143,14 @@ func TestPlatformAPIs(t *testing.T) {
}
`)
- testJavaError(t, "platform_apis must be true when sdk_version is empty.", `
+ testJavaError(t, "This module has conflicting settings. sdk_version is empty, which means that this module is build against platform APIs. However platform_apis is not set to true", `
android_app {
name: "bar",
srcs: ["b.java"],
}
`)
- testJavaError(t, "platform_apis must be false when sdk_version is not empty.", `
+ testJavaError(t, "This module has conflicting settings. sdk_version is not empty, which means this module cannot use platform APIs. However platform_apis is set to true.", `
android_app {
name: "bar",
srcs: ["b.java"],
@@ -428,7 +427,8 @@ func TestUpdatableApps_JniLibShouldBeBuiltAgainstMinSdkVersion(t *testing.T) {
name: "libjni",
stl: "none",
system_shared_libs: [],
- sdk_version: "29",
+ sdk_version: "current",
+ min_sdk_version: "29",
}
`
fs := map[string][]byte{
@@ -482,12 +482,13 @@ func TestUpdatableApps_ErrorIfJniLibDoesntSupportMinSdkVersion(t *testing.T) {
name: "libjni",
stl: "none",
sdk_version: "current",
+ min_sdk_version: "current",
}
`
- testJavaError(t, `"libjni" .*: sdk_version\(current\) is higher than min_sdk_version\(29\)`, bp)
+ testJavaError(t, `"libjni" .*: min_sdk_version\(current\) is higher than min_sdk_version\(29\)`, bp)
}
-func TestUpdatableApps_ErrorIfDepSdkVersionIsHigher(t *testing.T) {
+func TestUpdatableApps_ErrorIfDepMinSdkVersionIsHigher(t *testing.T) {
bp := cc.GatherRequiredDepsForTest(android.Android) + `
android_app {
name: "foo",
@@ -504,6 +505,7 @@ func TestUpdatableApps_ErrorIfDepSdkVersionIsHigher(t *testing.T) {
shared_libs: ["libbar"],
system_shared_libs: [],
sdk_version: "27",
+ min_sdk_version: "27",
}
cc_library {
@@ -511,6 +513,7 @@ func TestUpdatableApps_ErrorIfDepSdkVersionIsHigher(t *testing.T) {
stl: "none",
system_shared_libs: [],
sdk_version: "current",
+ min_sdk_version: "current",
}
`
testJavaError(t, `"libjni" .*: links "libbar" built against newer API version "current"`, bp)
@@ -1485,11 +1488,11 @@ func TestJNISDK(t *testing.T) {
func TestCertificates(t *testing.T) {
testCases := []struct {
- name string
- bp string
- certificateOverride string
- expectedLineage string
- expectedCertificate string
+ name string
+ bp string
+ certificateOverride string
+ expectedCertSigningFlags string
+ expectedCertificate string
}{
{
name: "default",
@@ -1500,9 +1503,9 @@ func TestCertificates(t *testing.T) {
sdk_version: "current",
}
`,
- certificateOverride: "",
- expectedLineage: "",
- expectedCertificate: "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8",
+ certificateOverride: "",
+ expectedCertSigningFlags: "",
+ expectedCertificate: "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8",
},
{
name: "module certificate property",
@@ -1519,9 +1522,9 @@ func TestCertificates(t *testing.T) {
certificate: "cert/new_cert",
}
`,
- certificateOverride: "",
- expectedLineage: "",
- expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
+ certificateOverride: "",
+ expectedCertSigningFlags: "",
+ expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
},
{
name: "path certificate property",
@@ -1533,9 +1536,9 @@ func TestCertificates(t *testing.T) {
sdk_version: "current",
}
`,
- certificateOverride: "",
- expectedLineage: "",
- expectedCertificate: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ certificateOverride: "",
+ expectedCertSigningFlags: "",
+ expectedCertificate: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
},
{
name: "certificate overrides",
@@ -1552,18 +1555,19 @@ func TestCertificates(t *testing.T) {
certificate: "cert/new_cert",
}
`,
- certificateOverride: "foo:new_certificate",
- expectedLineage: "",
- expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
+ certificateOverride: "foo:new_certificate",
+ expectedCertSigningFlags: "",
+ expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
},
{
- name: "certificate lineage",
+ name: "certificate signing flags",
bp: `
android_app {
name: "foo",
srcs: ["a.java"],
certificate: ":new_certificate",
lineage: "lineage.bin",
+ rotationMinSdkVersion: "32",
sdk_version: "current",
}
@@ -1572,18 +1576,19 @@ func TestCertificates(t *testing.T) {
certificate: "cert/new_cert",
}
`,
- certificateOverride: "",
- expectedLineage: "--lineage lineage.bin",
- expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
+ certificateOverride: "",
+ expectedCertSigningFlags: "--lineage lineage.bin --rotation-min-sdk-version 32",
+ expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
},
{
- name: "lineage from filegroup",
+ name: "cert signing flags from filegroup",
bp: `
android_app {
name: "foo",
srcs: ["a.java"],
certificate: ":new_certificate",
lineage: ":lineage_bin",
+ rotationMinSdkVersion: "32",
sdk_version: "current",
}
@@ -1597,9 +1602,9 @@ func TestCertificates(t *testing.T) {
srcs: ["lineage.bin"],
}
`,
- certificateOverride: "",
- expectedLineage: "--lineage lineage.bin",
- expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
+ certificateOverride: "",
+ expectedCertSigningFlags: "--lineage lineage.bin --rotation-min-sdk-version 32",
+ expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
},
}
@@ -1620,8 +1625,8 @@ func TestCertificates(t *testing.T) {
signCertificateFlags := signapk.Args["certificates"]
android.AssertStringEquals(t, "certificates flags", test.expectedCertificate, signCertificateFlags)
- signFlags := signapk.Args["flags"]
- android.AssertStringEquals(t, "signing flags", test.expectedLineage, signFlags)
+ certSigningFlags := signapk.Args["flags"]
+ android.AssertStringEquals(t, "cert signing flags", test.expectedCertSigningFlags, certSigningFlags)
})
}
}
@@ -1707,7 +1712,7 @@ func TestPackageNameOverride(t *testing.T) {
},
},
{
- name: "overridden",
+ name: "overridden via PRODUCT_PACKAGE_NAME_OVERRIDES",
bp: `
android_app {
name: "foo",
@@ -1722,6 +1727,22 @@ func TestPackageNameOverride(t *testing.T) {
"out/soong/target/product/test_device/system/app/bar/bar.apk",
},
},
+ {
+ name: "overridden via stem",
+ bp: `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ stem: "bar",
+ }
+ `,
+ packageNameOverride: "",
+ expected: []string{
+ "out/soong/.intermediates/foo/android_common/bar.apk",
+ "out/soong/target/product/test_device/system/app/bar/bar.apk",
+ },
+ },
}
for _, test := range testCases {
@@ -1737,7 +1758,7 @@ func TestPackageNameOverride(t *testing.T) {
foo := result.ModuleForTests("foo", "android_common")
- outSoongDir := result.Config.BuildDir()
+ outSoongDir := result.Config.SoongOutDir()
outputs := foo.AllOutputs()
outputMap := make(map[string]bool)
@@ -1800,6 +1821,7 @@ func TestOverrideAndroidApp(t *testing.T) {
base: "foo",
certificate: ":new_certificate",
lineage: "lineage.bin",
+ rotationMinSdkVersion: "32",
logging_parent: "bah",
}
@@ -1845,89 +1867,89 @@ func TestOverrideAndroidApp(t *testing.T) {
`)
expectedVariants := []struct {
- name string
- moduleName string
- variantName string
- apkName string
- apkPath string
- certFlag string
- lineageFlag string
- overrides []string
- packageFlag string
- renameResources bool
- logging_parent string
+ name string
+ moduleName string
+ variantName string
+ apkName string
+ apkPath string
+ certFlag string
+ certSigningFlags string
+ overrides []string
+ packageFlag string
+ renameResources bool
+ logging_parent string
}{
{
- name: "foo",
- moduleName: "foo",
- variantName: "android_common",
- apkPath: "out/soong/target/product/test_device/system/app/foo/foo.apk",
- certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
- lineageFlag: "",
- overrides: []string{"qux"},
- packageFlag: "",
- renameResources: false,
- logging_parent: "",
- },
- {
- name: "foo",
- moduleName: "bar",
- variantName: "android_common_bar",
- apkPath: "out/soong/target/product/test_device/system/app/bar/bar.apk",
- certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8",
- lineageFlag: "--lineage lineage.bin",
- overrides: []string{"qux", "foo"},
- packageFlag: "",
- renameResources: false,
- logging_parent: "bah",
- },
- {
- name: "foo",
- moduleName: "baz",
- variantName: "android_common_baz",
- apkPath: "out/soong/target/product/test_device/system/app/baz/baz.apk",
- certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
- lineageFlag: "",
- overrides: []string{"qux", "foo"},
- packageFlag: "org.dandroid.bp",
- renameResources: true,
- logging_parent: "",
- },
- {
- name: "foo",
- moduleName: "baz_no_rename_resources",
- variantName: "android_common_baz_no_rename_resources",
- apkPath: "out/soong/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk",
- certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
- lineageFlag: "",
- overrides: []string{"qux", "foo"},
- packageFlag: "org.dandroid.bp",
- renameResources: false,
- logging_parent: "",
- },
- {
- name: "foo_no_rename_resources",
- moduleName: "baz_base_no_rename_resources",
- variantName: "android_common_baz_base_no_rename_resources",
- apkPath: "out/soong/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk",
- certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
- lineageFlag: "",
- overrides: []string{"qux", "foo_no_rename_resources"},
- packageFlag: "org.dandroid.bp",
- renameResources: false,
- logging_parent: "",
- },
- {
- name: "foo_no_rename_resources",
- moduleName: "baz_override_base_rename_resources",
- variantName: "android_common_baz_override_base_rename_resources",
- apkPath: "out/soong/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk",
- certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
- lineageFlag: "",
- overrides: []string{"qux", "foo_no_rename_resources"},
- packageFlag: "org.dandroid.bp",
- renameResources: true,
- logging_parent: "",
+ name: "foo",
+ moduleName: "foo",
+ variantName: "android_common",
+ apkPath: "out/soong/target/product/test_device/system/app/foo/foo.apk",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ certSigningFlags: "",
+ overrides: []string{"qux"},
+ packageFlag: "",
+ renameResources: false,
+ logging_parent: "",
+ },
+ {
+ name: "foo",
+ moduleName: "bar",
+ variantName: "android_common_bar",
+ apkPath: "out/soong/target/product/test_device/system/app/bar/bar.apk",
+ certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8",
+ certSigningFlags: "--lineage lineage.bin --rotation-min-sdk-version 32",
+ overrides: []string{"qux", "foo"},
+ packageFlag: "",
+ renameResources: false,
+ logging_parent: "bah",
+ },
+ {
+ name: "foo",
+ moduleName: "baz",
+ variantName: "android_common_baz",
+ apkPath: "out/soong/target/product/test_device/system/app/baz/baz.apk",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ certSigningFlags: "",
+ overrides: []string{"qux", "foo"},
+ packageFlag: "org.dandroid.bp",
+ renameResources: true,
+ logging_parent: "",
+ },
+ {
+ name: "foo",
+ moduleName: "baz_no_rename_resources",
+ variantName: "android_common_baz_no_rename_resources",
+ apkPath: "out/soong/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ certSigningFlags: "",
+ overrides: []string{"qux", "foo"},
+ packageFlag: "org.dandroid.bp",
+ renameResources: false,
+ logging_parent: "",
+ },
+ {
+ name: "foo_no_rename_resources",
+ moduleName: "baz_base_no_rename_resources",
+ variantName: "android_common_baz_base_no_rename_resources",
+ apkPath: "out/soong/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ certSigningFlags: "",
+ overrides: []string{"qux", "foo_no_rename_resources"},
+ packageFlag: "org.dandroid.bp",
+ renameResources: false,
+ logging_parent: "",
+ },
+ {
+ name: "foo_no_rename_resources",
+ moduleName: "baz_override_base_rename_resources",
+ variantName: "android_common_baz_override_base_rename_resources",
+ apkPath: "out/soong/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ certSigningFlags: "",
+ overrides: []string{"qux", "foo_no_rename_resources"},
+ packageFlag: "org.dandroid.bp",
+ renameResources: true,
+ logging_parent: "",
},
}
for _, expected := range expectedVariants {
@@ -1941,13 +1963,13 @@ func TestOverrideAndroidApp(t *testing.T) {
certFlag := signapk.Args["certificates"]
android.AssertStringEquals(t, "certificates flags", expected.certFlag, certFlag)
- // Check the lineage flags
- lineageFlag := signapk.Args["flags"]
- android.AssertStringEquals(t, "signing flags", expected.lineageFlag, lineageFlag)
+ // Check the cert signing flags
+ certSigningFlags := signapk.Args["flags"]
+ android.AssertStringEquals(t, "cert signing flags", expected.certSigningFlags, certSigningFlags)
// Check if the overrides field values are correctly aggregated.
mod := variant.Module().(*AndroidApp)
- android.AssertDeepEquals(t, "overrides property", expected.overrides, mod.appProperties.Overrides)
+ android.AssertDeepEquals(t, "overrides property", expected.overrides, mod.overridableAppProperties.Overrides)
// Test Overridable property: Logging_parent
logging_parent := mod.aapt.LoggingParent
@@ -1965,6 +1987,173 @@ func TestOverrideAndroidApp(t *testing.T) {
}
}
+func TestOverrideAndroidAppOverrides(t *testing.T) {
+ ctx, _ := testJava(
+ t, `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ overrides: ["qux"]
+ }
+
+ android_app {
+ name: "bar",
+ srcs: ["b.java"],
+ sdk_version: "current",
+ overrides: ["foo"]
+ }
+
+ override_android_app {
+ name: "foo_override",
+ base: "foo",
+ overrides: ["bar"]
+ }
+ `)
+
+ expectedVariants := []struct {
+ name string
+ moduleName string
+ variantName string
+ overrides []string
+ }{
+ {
+ name: "foo",
+ moduleName: "foo",
+ variantName: "android_common",
+ overrides: []string{"qux"},
+ },
+ {
+ name: "bar",
+ moduleName: "bar",
+ variantName: "android_common",
+ overrides: []string{"foo"},
+ },
+ {
+ name: "foo",
+ moduleName: "foo_override",
+ variantName: "android_common_foo_override",
+ overrides: []string{"bar", "foo"},
+ },
+ }
+ for _, expected := range expectedVariants {
+ variant := ctx.ModuleForTests(expected.name, expected.variantName)
+
+ // Check if the overrides field values are correctly aggregated.
+ mod := variant.Module().(*AndroidApp)
+ android.AssertDeepEquals(t, "overrides property", expected.overrides, mod.overridableAppProperties.Overrides)
+ }
+}
+
+func TestOverrideAndroidAppWithPrebuilt(t *testing.T) {
+ result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(
+ t, `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ }
+
+ override_android_app {
+ name: "bar",
+ base: "foo",
+ }
+
+ android_app_import {
+ name: "bar",
+ prefer: true,
+ apk: "bar.apk",
+ presigned: true,
+ }
+ `)
+
+ // An app that has an override that also has a prebuilt should not be hidden.
+ foo := result.ModuleForTests("foo", "android_common")
+ if foo.Module().IsHideFromMake() {
+ t.Errorf("expected foo to have HideFromMake false")
+ }
+
+ // An override that also has a prebuilt should be hidden.
+ barOverride := result.ModuleForTests("foo", "android_common_bar")
+ if !barOverride.Module().IsHideFromMake() {
+ t.Errorf("expected bar override variant of foo to have HideFromMake true")
+ }
+}
+
+func TestOverrideAndroidAppStem(t *testing.T) {
+ ctx, _ := testJava(t, `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ }
+ override_android_app {
+ name: "bar",
+ base: "foo",
+ }
+ override_android_app {
+ name: "baz",
+ base: "foo",
+ stem: "baz_stem",
+ }
+ android_app {
+ name: "foo2",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ stem: "foo2_stem",
+ }
+ override_android_app {
+ name: "bar2",
+ base: "foo2",
+ }
+ override_android_app {
+ name: "baz2",
+ base: "foo2",
+ stem: "baz2_stem",
+ }
+ `)
+ for _, expected := range []struct {
+ moduleName string
+ variantName string
+ apkPath string
+ }{
+ {
+ moduleName: "foo",
+ variantName: "android_common",
+ apkPath: "out/soong/target/product/test_device/system/app/foo/foo.apk",
+ },
+ {
+ moduleName: "foo",
+ variantName: "android_common_bar",
+ apkPath: "out/soong/target/product/test_device/system/app/bar/bar.apk",
+ },
+ {
+ moduleName: "foo",
+ variantName: "android_common_baz",
+ apkPath: "out/soong/target/product/test_device/system/app/baz_stem/baz_stem.apk",
+ },
+ {
+ moduleName: "foo2",
+ variantName: "android_common",
+ apkPath: "out/soong/target/product/test_device/system/app/foo2_stem/foo2_stem.apk",
+ },
+ {
+ moduleName: "foo2",
+ variantName: "android_common_bar2",
+ // Note that this may cause the duplicate output error.
+ apkPath: "out/soong/target/product/test_device/system/app/foo2_stem/foo2_stem.apk",
+ },
+ {
+ moduleName: "foo2",
+ variantName: "android_common_baz2",
+ apkPath: "out/soong/target/product/test_device/system/app/baz2_stem/baz2_stem.apk",
+ },
+ } {
+ variant := ctx.ModuleForTests(expected.moduleName, expected.variantName)
+ variant.Output(expected.apkPath)
+ }
+}
+
func TestOverrideAndroidAppDependency(t *testing.T) {
ctx, _ := testJava(t, `
android_app {
@@ -2071,9 +2260,9 @@ func TestOverrideAndroidTest(t *testing.T) {
// Check if the overrides field values are correctly aggregated.
mod := variant.Module().(*AndroidTest)
- if !reflect.DeepEqual(expected.overrides, mod.appProperties.Overrides) {
+ if !reflect.DeepEqual(expected.overrides, mod.overridableAppProperties.Overrides) {
t.Errorf("Incorrect overrides property value, expected: %q, got: %q",
- expected.overrides, mod.appProperties.Overrides)
+ expected.overrides, mod.overridableAppProperties.Overrides)
}
// Check if javac classpath has the correct jar file path. This checks instrumentation_for overrides.
@@ -2168,10 +2357,33 @@ func TestAndroidTest_FixTestConfig(t *testing.T) {
t.Errorf("test_config_fixer was not expected to run, but did: %q", params.RuleParams.Command)
}
}
-
}
}
+func TestInstrumentationTargetPrebuilt(t *testing.T) {
+ bp := `
+ android_app_import {
+ name: "foo",
+ apk: "foo.apk",
+ presigned: true,
+ }
+
+ android_test {
+ name: "bar",
+ srcs: ["a.java"],
+ instrumentation_for: "foo",
+ sdk_version: "current",
+ }
+ `
+
+ android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ ).ExtendWithErrorHandler(
+ android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+ "instrumentation_for: dependency \"foo\" of type \"android_app_import\" does not provide JavaInfo so is unsuitable for use with this property")).
+ RunTestWithBp(t, bp)
+}
+
func TestStl(t *testing.T) {
ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
cc_library {
@@ -2285,6 +2497,49 @@ func TestUsesLibraries(t *testing.T) {
sdk_version: "current",
}
+ java_library {
+ name: "runtime-required-x",
+ srcs: ["a.java"],
+ installable: true,
+ sdk_version: "current",
+ }
+
+ java_library {
+ name: "runtime-optional-x",
+ srcs: ["a.java"],
+ installable: true,
+ sdk_version: "current",
+ }
+
+ android_library {
+ name: "static-x",
+ uses_libs: ["runtime-required-x"],
+ optional_uses_libs: ["runtime-optional-x"],
+ sdk_version: "current",
+ }
+
+ java_library {
+ name: "runtime-required-y",
+ srcs: ["a.java"],
+ installable: true,
+ sdk_version: "current",
+ }
+
+ java_library {
+ name: "runtime-optional-y",
+ srcs: ["a.java"],
+ installable: true,
+ sdk_version: "current",
+ }
+
+ java_library {
+ name: "static-y",
+ srcs: ["a.java"],
+ uses_libs: ["runtime-required-y"],
+ optional_uses_libs: ["runtime-optional-y"],
+ sdk_version: "current",
+ }
+
// A library that has to use "provides_uses_lib", because:
// - it is not an SDK library
// - its library name is different from its module name
@@ -2307,6 +2562,8 @@ func TestUsesLibraries(t *testing.T) {
// statically linked component libraries should not pull their SDK libraries,
// so "fred" should not be added to class loader context
"fred.stubs",
+ "static-x",
+ "static-y",
],
uses_libs: [
"foo",
@@ -2353,11 +2610,8 @@ func TestUsesLibraries(t *testing.T) {
expectManifestFixerArgs := `--extract-native-libs=true ` +
`--uses-library qux ` +
`--uses-library quuz ` +
- `--uses-library foo ` + // TODO(b/132357300): "foo" should not be passed to manifest_fixer
- `--uses-library com.non.sdk.lib ` + // TODO(b/132357300): "com.non.sdk.lib" should not be passed to manifest_fixer
- `--uses-library bar ` + // TODO(b/132357300): "bar" should not be passed to manifest_fixer
`--uses-library runtime-library`
- android.AssertStringEquals(t, "manifest_fixer args", expectManifestFixerArgs, actualManifestFixerArgs)
+ android.AssertStringDoesContain(t, "manifest_fixer args", actualManifestFixerArgs, expectManifestFixerArgs)
// Test that all libraries are verified (library order matters).
verifyCmd := app.Rule("verify_uses_libraries").RuleParams.Command
@@ -2366,8 +2620,12 @@ func TestUsesLibraries(t *testing.T) {
`--uses-library qux ` +
`--uses-library quuz ` +
`--uses-library runtime-library ` +
+ `--uses-library runtime-required-x ` +
+ `--uses-library runtime-required-y ` +
`--optional-uses-library bar ` +
- `--optional-uses-library baz `
+ `--optional-uses-library baz ` +
+ `--optional-uses-library runtime-optional-x ` +
+ `--optional-uses-library runtime-optional-y `
android.AssertStringDoesContain(t, "verify cmd args", verifyCmd, verifyArgs)
// Test that all libraries are verified for an APK (library order matters).
@@ -2387,7 +2645,11 @@ func TestUsesLibraries(t *testing.T) {
`PCL[/system/framework/foo.jar]#` +
`PCL[/system/framework/non-sdk-lib.jar]#` +
`PCL[/system/framework/bar.jar]#` +
- `PCL[/system/framework/runtime-library.jar]`
+ `PCL[/system/framework/runtime-library.jar]#` +
+ `PCL[/system/framework/runtime-required-x.jar]#` +
+ `PCL[/system/framework/runtime-optional-x.jar]#` +
+ `PCL[/system/framework/runtime-required-y.jar]#` +
+ `PCL[/system/framework/runtime-optional-y.jar] `
android.AssertStringDoesContain(t, "dexpreopt app cmd args", cmd, w)
// Test conditional context for target SDK version 28.
@@ -2471,7 +2733,7 @@ func TestDexpreoptBcp(t *testing.T) {
PrepareForTestWithJavaSdkLibraryFiles,
FixtureWithLastReleaseApis("runtime-library", "foo", "bar"),
dexpreopt.FixtureSetBootJars("platform:foo"),
- dexpreopt.FixtureSetUpdatableBootJars("platform:bar"),
+ dexpreopt.FixtureSetApexBootJars("platform:bar"),
dexpreopt.FixtureSetPreoptWithUpdatableBcp(test.with),
).RunTestWithBp(t, bp)
@@ -2559,116 +2821,6 @@ func TestCodelessApp(t *testing.T) {
}
}
-func TestEmbedNotice(t *testing.T) {
- result := android.GroupFixturePreparers(
- PrepareForTestWithJavaDefaultModules,
- cc.PrepareForTestWithCcDefaultModules,
- genrule.PrepareForTestWithGenRuleBuildComponents,
- android.MockFS{
- "APP_NOTICE": nil,
- "GENRULE_NOTICE": nil,
- "LIB_NOTICE": nil,
- "TOOL_NOTICE": nil,
- }.AddToFixture(),
- ).RunTestWithBp(t, `
- android_app {
- name: "foo",
- srcs: ["a.java"],
- static_libs: ["javalib"],
- jni_libs: ["libjni"],
- notice: "APP_NOTICE",
- embed_notices: true,
- sdk_version: "current",
- }
-
- // No embed_notice flag
- android_app {
- name: "bar",
- srcs: ["a.java"],
- jni_libs: ["libjni"],
- notice: "APP_NOTICE",
- sdk_version: "current",
- }
-
- // No NOTICE files
- android_app {
- name: "baz",
- srcs: ["a.java"],
- embed_notices: true,
- sdk_version: "current",
- }
-
- cc_library {
- name: "libjni",
- system_shared_libs: [],
- stl: "none",
- notice: "LIB_NOTICE",
- sdk_version: "current",
- }
-
- java_library {
- name: "javalib",
- srcs: [
- ":gen",
- ],
- sdk_version: "current",
- }
-
- genrule {
- name: "gen",
- tools: ["gentool"],
- out: ["gen.java"],
- notice: "GENRULE_NOTICE",
- }
-
- java_binary_host {
- name: "gentool",
- srcs: ["b.java"],
- notice: "TOOL_NOTICE",
- }
- `)
-
- // foo has NOTICE files to process, and embed_notices is true.
- foo := result.ModuleForTests("foo", "android_common")
- // verify merge notices rule.
- mergeNotices := foo.Rule("mergeNoticesRule")
- noticeInputs := mergeNotices.Inputs.Strings()
- // TOOL_NOTICE should be excluded as it's a host module.
- if len(mergeNotices.Inputs) != 3 {
- t.Errorf("number of input notice files: expected = 3, actual = %q", noticeInputs)
- }
- if !inList("APP_NOTICE", noticeInputs) {
- t.Errorf("APP_NOTICE is missing from notice files, %q", noticeInputs)
- }
- if !inList("LIB_NOTICE", noticeInputs) {
- t.Errorf("LIB_NOTICE is missing from notice files, %q", noticeInputs)
- }
- if !inList("GENRULE_NOTICE", noticeInputs) {
- t.Errorf("GENRULE_NOTICE is missing from notice files, %q", noticeInputs)
- }
- // aapt2 flags should include -A <NOTICE dir> so that its contents are put in the APK's /assets.
- res := foo.Output("package-res.apk")
- aapt2Flags := res.Args["flags"]
- e := "-A out/soong/.intermediates/foo/android_common/NOTICE"
- android.AssertStringDoesContain(t, "expected.apkPath", aapt2Flags, e)
-
- // bar has NOTICE files to process, but embed_notices is not set.
- bar := result.ModuleForTests("bar", "android_common")
- res = bar.Output("package-res.apk")
- aapt2Flags = res.Args["flags"]
- e = "-A out/soong/.intermediates/bar/android_common/NOTICE"
- android.AssertStringDoesNotContain(t, "bar shouldn't have the asset dir flag for NOTICE", aapt2Flags, e)
-
- // baz's embed_notice is true, but it doesn't have any NOTICE files.
- baz := result.ModuleForTests("baz", "android_common")
- res = baz.Output("package-res.apk")
- aapt2Flags = res.Args["flags"]
- e = "-A out/soong/.intermediates/baz/android_common/NOTICE"
- if strings.Contains(aapt2Flags, e) {
- t.Errorf("baz shouldn't have the asset dir flag for NOTICE: %q", e)
- }
-}
-
func TestUncompressDex(t *testing.T) {
testCases := []struct {
name string
@@ -2823,3 +2975,97 @@ func TestExportedProguardFlagFiles(t *testing.T) {
t.Errorf("App does not use library proguard config")
}
}
+
+func TestTargetSdkVersionManifestFixer(t *testing.T) {
+ platform_sdk_codename := "Tiramisu"
+ testCases := []struct {
+ name string
+ targetSdkVersionInBp string
+ targetSdkVersionExpected string
+ unbundledBuild bool
+ }{
+ {
+ name: "Non-Unbundled build: Android.bp has targetSdkVersion",
+ targetSdkVersionInBp: "30",
+ targetSdkVersionExpected: "30",
+ unbundledBuild: false,
+ },
+ {
+ name: "Unbundled build: Android.bp has targetSdkVersion",
+ targetSdkVersionInBp: "30",
+ targetSdkVersionExpected: "30",
+ unbundledBuild: true,
+ },
+ {
+ name: "Non-Unbundled build: Android.bp has targetSdkVersion equal to platform_sdk_codename",
+ targetSdkVersionInBp: platform_sdk_codename,
+ targetSdkVersionExpected: platform_sdk_codename,
+ unbundledBuild: false,
+ },
+ {
+ name: "Unbundled build: Android.bp has targetSdkVersion equal to platform_sdk_codename",
+ targetSdkVersionInBp: platform_sdk_codename,
+ targetSdkVersionExpected: "10000",
+ unbundledBuild: true,
+ },
+
+ {
+ name: "Non-Unbundled build: Android.bp has no targetSdkVersion",
+ targetSdkVersionExpected: platform_sdk_codename,
+ unbundledBuild: false,
+ },
+ {
+ name: "Unbundled build: Android.bp has no targetSdkVersion",
+ targetSdkVersionExpected: "10000",
+ unbundledBuild: true,
+ },
+ }
+ for _, testCase := range testCases {
+ bp := fmt.Sprintf(`
+ android_app {
+ name: "foo",
+ sdk_version: "current",
+ target_sdk_version: "%v",
+ }
+ `, testCase.targetSdkVersionInBp)
+ fixture := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ // explicitly set platform_sdk_codename to make the test deterministic
+ variables.Platform_sdk_codename = &platform_sdk_codename
+ variables.Platform_version_active_codenames = []string{platform_sdk_codename}
+ // create a non-empty list if unbundledBuild==true
+ if testCase.unbundledBuild {
+ variables.Unbundled_build_apps = []string{"apex_a", "apex_b"}
+ }
+ }),
+ )
+
+ result := fixture.RunTestWithBp(t, bp)
+ foo := result.ModuleForTests("foo", "android_common")
+
+ manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
+ android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected)
+ }
+}
+
+func TestAppMissingCertificateAllowMissingDependencies(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.PrepareForTestWithAllowMissingDependencies,
+ android.PrepareForTestWithAndroidMk,
+ ).RunTestWithBp(t, `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ certificate: ":missing_certificate",
+ sdk_version: "current",
+ }`)
+
+ foo := result.ModuleForTests("foo", "android_common")
+ fooApk := foo.Output("foo.apk")
+ if fooApk.Rule != android.ErrorRule {
+ t.Fatalf("expected ErrorRule for foo.apk, got %s", fooApk.Rule.String())
+ }
+ android.AssertStringDoesContain(t, "expected error rule message", fooApk.Args["error"], "missing dependencies: missing_certificate\n")
+}
diff --git a/java/base.go b/java/base.go
index df70efb44..7aa281495 100644
--- a/java/base.go
+++ b/java/base.go
@@ -155,6 +155,13 @@ type CommonProperties struct {
// List of java_plugin modules that provide extra errorprone checks.
Extra_check_modules []string
+
+ // This property can be in 3 states. When set to true, errorprone will
+ // be run during the regular build. When set to false, errorprone will
+ // never be run. When unset, errorprone will be run when the RUN_ERROR_PRONE
+ // environment variable is true. Setting this to false will improve build
+ // performance more than adding -XepDisableAllChecks in javacflags.
+ Enabled *bool
}
Proto struct {
@@ -163,6 +170,9 @@ type CommonProperties struct {
}
Instrument bool `blueprint:"mutated"`
+ // If true, then the module supports statically including the jacocoagent
+ // into the library.
+ Supports_static_instrumentation bool `blueprint:"mutated"`
// List of files to include in the META-INF/services folder of the resulting jar.
Services []string `android:"path,arch_variant"`
@@ -177,21 +187,30 @@ type CommonProperties struct {
// Properties that are specific to device modules. Host module factories should not add these when
// constructing a new module.
type DeviceProperties struct {
- // if not blank, set to the version of the sdk to compile against.
- // Defaults to compiling against the current platform.
+ // If not blank, set to the version of the sdk to compile against.
+ // Defaults to private.
+ // Values are of one of the following forms:
+ // 1) numerical API level, "current", "none", or "core_platform"
+ // 2) An SDK kind with an API level: "<sdk kind>_<API level>"
+ // See build/soong/android/sdk_version.go for the complete and up to date list of SDK kinds.
+ // If the SDK kind is empty, it will be set to public.
Sdk_version *string
// if not blank, set the minimum version of the sdk that the compiled artifacts will run against.
- // Defaults to sdk_version if not set.
+ // Defaults to sdk_version if not set. See sdk_version for possible values.
Min_sdk_version *string
+ // if not blank, set the maximum version of the sdk that the compiled artifacts will run against.
+ // Defaults to empty string "". See sdk_version for possible values.
+ Max_sdk_version *string
+
// if not blank, set the targetSdkVersion in the AndroidManifest.xml.
- // Defaults to sdk_version if not set.
+ // Defaults to sdk_version if not set. See sdk_version for possible values.
Target_sdk_version *string
// Whether to compile against the platform APIs instead of an SDK.
// If true, then sdk_version must be empty. The value of this field
- // is ignored when module's type isn't android_app.
+ // is ignored when module's type isn't android_app, android_test, or android_test_helper_app.
Platform_apis *bool
Aidl struct {
@@ -211,6 +230,12 @@ type DeviceProperties struct {
// whether to generate Binder#GetTransaction name method.
Generate_get_transaction_name *bool
+ // whether all interfaces should be annotated with required permissions.
+ Enforce_permissions *bool
+
+ // allowlist for interfaces that (temporarily) do not require annotation for permissions.
+ Enforce_permissions_exceptions []string `android:"path"`
+
// list of flags that will be passed to the AIDL compiler
Flags []string
}
@@ -229,9 +254,6 @@ type DeviceProperties struct {
// otherwise provides defaults libraries to add to the bootclasspath.
System_modules *string
- // set the name of the output
- Stem *string
-
IsSDKLibrary bool `blueprint:"mutated"`
// If true, generate the signature file of APK Signing Scheme V4, along side the signed APK file.
@@ -243,6 +265,15 @@ type DeviceProperties struct {
SyspropPublicStub string `blueprint:"mutated"`
}
+// Device properties that can be overridden by overriding module (e.g. override_android_app)
+type OverridableDeviceProperties struct {
+ // set the name of the output. If not set, `name` is used.
+ // To override a module with this property set, overriding module might need to set this as well.
+ // Otherwise, both the overridden and the overriding modules will have the same output name, which
+ // can cause the duplicate output error.
+ Stem *string
+}
+
// Functionality common to Module and Import
//
// It is embedded in Module so its functionality can be used by methods in Module
@@ -269,12 +300,94 @@ func (e *embeddableInModuleAndImport) depIsInSameApex(ctx android.BaseModuleCont
return false
}
+// OptionalDexJarPath can be either unset, hold a valid path to a dex jar file,
+// or an invalid path describing the reason it is invalid.
+//
+// It is unset if a dex jar isn't applicable, i.e. no build rule has been
+// requested to create one.
+//
+// If a dex jar has been requested to be built then it is set, and it may be
+// either a valid android.Path, or invalid with a reason message. The latter
+// happens if the source that should produce the dex file isn't able to.
+//
+// E.g. it is invalid with a reason message if there is a prebuilt APEX that
+// could produce the dex jar through a deapexer module, but the APEX isn't
+// installable so doing so wouldn't be safe.
+type OptionalDexJarPath struct {
+ isSet bool
+ path android.OptionalPath
+}
+
+// IsSet returns true if a path has been set, either invalid or valid.
+func (o OptionalDexJarPath) IsSet() bool {
+ return o.isSet
+}
+
+// Valid returns true if there is a path that is valid.
+func (o OptionalDexJarPath) Valid() bool {
+ return o.isSet && o.path.Valid()
+}
+
+// Path returns the valid path, or panics if it's either not set or is invalid.
+func (o OptionalDexJarPath) Path() android.Path {
+ if !o.isSet {
+ panic("path isn't set")
+ }
+ return o.path.Path()
+}
+
+// PathOrNil returns the path if it's set and valid, or else nil.
+func (o OptionalDexJarPath) PathOrNil() android.Path {
+ if o.Valid() {
+ return o.Path()
+ }
+ return nil
+}
+
+// InvalidReason returns the reason for an invalid path, which is never "". It
+// returns "" for an unset or valid path.
+func (o OptionalDexJarPath) InvalidReason() string {
+ if !o.isSet {
+ return ""
+ }
+ return o.path.InvalidReason()
+}
+
+func (o OptionalDexJarPath) String() string {
+ if !o.isSet {
+ return "<unset>"
+ }
+ return o.path.String()
+}
+
+// makeUnsetDexJarPath returns an unset OptionalDexJarPath.
+func makeUnsetDexJarPath() OptionalDexJarPath {
+ return OptionalDexJarPath{isSet: false}
+}
+
+// makeDexJarPathFromOptionalPath returns an OptionalDexJarPath that is set with
+// the given OptionalPath, which may be valid or invalid.
+func makeDexJarPathFromOptionalPath(path android.OptionalPath) OptionalDexJarPath {
+ return OptionalDexJarPath{isSet: true, path: path}
+}
+
+// makeDexJarPathFromPath returns an OptionalDexJarPath that is set with the
+// valid given path. It returns an unset OptionalDexJarPath if the given path is
+// nil.
+func makeDexJarPathFromPath(path android.Path) OptionalDexJarPath {
+ if path == nil {
+ return makeUnsetDexJarPath()
+ }
+ return makeDexJarPathFromOptionalPath(android.OptionalPathForPath(path))
+}
+
// Module contains the properties and members used by all java module types
type Module struct {
android.ModuleBase
android.DefaultableModuleBase
android.ApexModuleBase
android.SdkBase
+ android.BazelModuleBase
// Functionality common to Module and Import.
embeddableInModuleAndImport
@@ -283,6 +396,8 @@ type Module struct {
protoProperties android.ProtoProperties
deviceProperties DeviceProperties
+ overridableDeviceProperties OverridableDeviceProperties
+
// jar file containing header classes including static library dependencies, suitable for
// inserting into the bootclasspath/classpath of another compile
headerJarFile android.Path
@@ -303,7 +418,7 @@ type Module struct {
implementationAndResourcesJar android.Path
// output file containing classes.dex and resources
- dexJarFile android.Path
+ dexJarFile OptionalDexJarPath
// output file containing uninstrumented classes that will be instrumented by jacoco
jacocoReportClassesFile android.Path
@@ -312,13 +427,17 @@ type Module struct {
outputFile android.Path
extraOutputFiles android.Paths
- exportAidlIncludeDirs android.Paths
+ exportAidlIncludeDirs android.Paths
+ ignoredAidlPermissionList android.Paths
logtagsSrcs android.Paths
// installed file for binary dependency
installFile android.Path
+ // installed file for hostdex copy
+ hostdexInstallFile android.InstallPath
+
// list of .java files and srcjars that was passed to javac
compiledJavaSrcs android.Paths
compiledSrcJars android.Paths
@@ -345,9 +464,6 @@ type Module struct {
// expanded Jarjar_rules
expandJarjarRules android.Path
- // list of additional targets for checkbuild
- additionalCheckedModules android.Paths
-
// Extra files generated by the module type to be added as java resources.
extraResources android.Paths
@@ -367,6 +483,9 @@ type Module struct {
sdkVersion android.SdkSpec
minSdkVersion android.SdkSpec
+ maxSdkVersion android.SdkSpec
+
+ sourceExtensions []string
}
func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
@@ -375,7 +494,7 @@ func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
return nil
}
if sdkVersion.Kind == android.SdkCorePlatform {
- if useLegacyCorePlatformApiByName(j.BaseModuleName()) {
+ if useLegacyCorePlatformApi(ctx, j.BaseModuleName()) {
return fmt.Errorf("non stable SDK %v - uses legacy core platform", sdkVersion)
} else {
// Treat stable core platform as stable.
@@ -417,9 +536,9 @@ func (j *Module) checkPlatformAPI(ctx android.ModuleContext) {
usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis)
sdkVersionSpecified := sc.SdkVersion(ctx).Specified()
if usePlatformAPI && sdkVersionSpecified {
- ctx.PropertyErrorf("platform_apis", "platform_apis must be false when sdk_version is not empty.")
+ ctx.PropertyErrorf("platform_apis", "This module has conflicting settings. sdk_version is not empty, which means this module cannot use platform APIs. However platform_apis is set to true.")
} else if !usePlatformAPI && !sdkVersionSpecified {
- ctx.PropertyErrorf("platform_apis", "platform_apis must be true when sdk_version is empty.")
+ ctx.PropertyErrorf("platform_apis", "This module has conflicting settings. sdk_version is empty, which means that this module is build against platform APIs. However platform_apis is not set to true")
}
}
@@ -437,6 +556,7 @@ func (j *Module) addHostAndDeviceProperties() {
j.addHostProperties()
j.AddProperties(
&j.deviceProperties,
+ &j.overridableDeviceProperties,
&j.dexer.dexProperties,
&j.dexpreoptProperties,
&j.linter.properties,
@@ -488,7 +608,8 @@ func (j *Module) shouldInstrument(ctx android.BaseModuleContext) bool {
}
func (j *Module) shouldInstrumentStatic(ctx android.BaseModuleContext) bool {
- return j.shouldInstrument(ctx) &&
+ return j.properties.Supports_static_instrumentation &&
+ j.shouldInstrument(ctx) &&
(ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_STATIC") ||
ctx.Config().UnbundledBuild())
}
@@ -524,6 +645,13 @@ func (j *Module) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
return j.SdkVersion(ctx)
}
+func (j *Module) MaxSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ maxSdkVersion := proptools.StringDefault(j.deviceProperties.Max_sdk_version, "")
+ // SdkSpecFrom returns SdkSpecPrivate for this, which may be confusing.
+ // TODO(b/208456999): ideally MaxSdkVersion should be an ApiLevel and not SdkSpec.
+ return android.SdkSpecFrom(ctx, maxSdkVersion)
+}
+
func (j *Module) MinSdkVersionString() string {
return j.minSdkVersion.Raw
}
@@ -598,7 +726,10 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) {
if dep != nil {
if component, ok := dep.(SdkLibraryComponentDependency); ok {
if lib := component.OptionalSdkLibraryImplementation(); lib != nil {
- ctx.AddVariationDependencies(nil, usesLibTag, *lib)
+ // Add library as optional if it's one of the optional compatibility libs.
+ optional := android.InList(*lib, dexpreopt.OptionalCompatUsesLibs)
+ tag := makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, optional, true)
+ ctx.AddVariationDependencies(nil, tag, *lib)
}
}
}
@@ -633,6 +764,11 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) {
} else if j.shouldInstrumentStatic(ctx) {
ctx.AddVariationDependencies(nil, staticLibTag, "jacocoagent")
}
+
+ if j.useCompose() {
+ ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), kotlinPluginTag,
+ "androidx.compose.compiler_compiler-hosted")
+ }
}
func hasSrcExt(srcs []string, ext string) bool {
@@ -649,6 +785,17 @@ func (j *Module) hasSrcExt(ext string) bool {
return hasSrcExt(j.properties.Srcs, ext)
}
+func (j *Module) individualAidlFlags(ctx android.ModuleContext, aidlFile android.Path) string {
+ var flags string
+
+ if Bool(j.deviceProperties.Aidl.Enforce_permissions) {
+ if !android.InList(aidlFile.String(), j.ignoredAidlPermissionList.Strings()) {
+ flags = "-Wmissing-permission-annotation -Werror"
+ }
+ }
+ return flags
+}
+
func (j *Module) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath,
aidlIncludeDirs android.Paths) (string, android.Paths) {
@@ -691,6 +838,14 @@ func (j *Module) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.Opt
flags = append(flags, "--transaction_names")
}
+ if Bool(j.deviceProperties.Aidl.Enforce_permissions) {
+ exceptions := j.deviceProperties.Aidl.Enforce_permissions_exceptions
+ j.ignoredAidlPermissionList = android.PathsForModuleSrcExcludes(ctx, exceptions, nil)
+ }
+
+ aidlMinSdkVersion := j.MinSdkVersion(ctx).ApiLevel.String()
+ flags = append(flags, "--min_sdk_version="+aidlMinSdkVersion)
+
return strings.Join(flags, " "), deps
}
@@ -701,7 +856,8 @@ func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaB
// javaVersion flag.
flags.javaVersion = getJavaVersion(ctx, String(j.properties.Java_version), android.SdkContext(j))
- if ctx.Config().RunErrorProne() {
+ epEnabled := j.properties.Errorprone.Enabled
+ if (ctx.Config().RunErrorProne() && epEnabled == nil) || Bool(epEnabled) {
if config.ErrorProneClasspath == nil && ctx.Config().TestProductVariables == nil {
ctx.ModuleErrorf("cannot build with Error Prone, missing external/error_prone?")
}
@@ -712,7 +868,7 @@ func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaB
}
errorProneFlags = append(errorProneFlags, j.properties.Errorprone.Javacflags...)
- flags.errorProneExtraJavacFlags = "${config.ErrorProneFlags} " +
+ flags.errorProneExtraJavacFlags = "${config.ErrorProneHeapFlags} ${config.ErrorProneFlags} " +
"'" + strings.Join(errorProneFlags, " ") + "'"
flags.errorProneProcessorPath = classpath(android.PathsForSource(ctx, config.ErrorProneClasspath))
}
@@ -720,6 +876,7 @@ func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaB
// classpath
flags.bootClasspath = append(flags.bootClasspath, deps.bootClasspath...)
flags.classpath = append(flags.classpath, deps.classpath...)
+ flags.dexClasspath = append(flags.dexClasspath, deps.dexClasspath...)
flags.java9Classpath = append(flags.java9Classpath, deps.java9Classpath...)
flags.processorPath = append(flags.processorPath, deps.processorPath...)
flags.errorProneProcessorPath = append(flags.errorProneProcessorPath, deps.errorProneProcessorPath...)
@@ -780,7 +937,7 @@ func (j *Module) collectJavacFlags(
// Manually specify build directory in case it is not under the repo root.
// (javac doesn't seem to expand into symbolic links when searching for patch-module targets, so
// just adding a symlink under the root doesn't help.)
- patchPaths := []string{".", ctx.Config().BuildDir()}
+ patchPaths := []string{".", ctx.Config().SoongOutDir()}
// b/150878007
//
@@ -832,6 +989,14 @@ func (j *Module) collectJavacFlags(
return flags
}
+func (j *Module) AddJSONData(d *map[string]interface{}) {
+ (&j.ModuleBase).AddJSONData(d)
+ (*d)["Java"] = map[string]interface{}{
+ "SourceExtensions": j.sourceExtensions,
+ }
+
+}
+
func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
@@ -841,7 +1006,14 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
if flags.javaVersion.usesJavaModules() {
j.properties.Srcs = append(j.properties.Srcs, j.properties.Openjdk9.Srcs...)
}
+
srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
+ j.sourceExtensions = []string{}
+ for _, ext := range []string{".kt", ".proto", ".aidl", ".java", ".logtags"} {
+ if hasSrcExt(srcFiles.Strings(), ext) {
+ j.sourceExtensions = append(j.sourceExtensions, ext)
+ }
+ }
if hasSrcExt(srcFiles.Strings(), ".proto") {
flags = protoFlags(ctx, &j.properties, &j.protoProperties, flags)
}
@@ -862,6 +1034,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
if aaptSrcJar != nil {
srcJars = append(srcJars, aaptSrcJar)
}
+ srcFiles = srcFiles.FilterOutByExt(".srcjar")
if j.properties.Jarjar_rules != nil {
j.expandJarjarRules = android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
@@ -879,18 +1052,30 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
}
}
+ // We don't currently run annotation processors in turbine, which means we can't use turbine
+ // generated header jars when an annotation processor that generates API is enabled. One
+ // exception (handled further below) is when kotlin sources are enabled, in which case turbine
+ // is used to run all of the annotation processors.
+ disableTurbine := deps.disableTurbine
+
// Collect .java files for AIDEGen
j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, uniqueSrcFiles.Strings()...)
var kotlinJars android.Paths
+ var kotlinHeaderJars android.Paths
if srcFiles.HasExt(".kt") {
+ // When using kotlin sources turbine is used to generate annotation processor sources,
+ // including for annotation processors that generate API, so we can use turbine for
+ // java sources too.
+ disableTurbine = false
+
// user defined kotlin flags.
kotlincFlags := j.properties.Kotlincflags
CheckKotlincFlags(ctx, kotlincFlags)
- // Dogfood the JVM_IR backend.
- kotlincFlags = append(kotlincFlags, "-Xuse-ir")
+ // Workaround for KT-46512
+ kotlincFlags = append(kotlincFlags, "-Xsam-conversions=class")
// If there are kotlin files, compile them first but pass all the kotlin and java files
// kotlinc will use the java files to resolve types referenced by the kotlin files, but
@@ -899,6 +1084,12 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
if ctx.Device() {
kotlincFlags = append(kotlincFlags, "-no-jdk")
}
+
+ for _, plugin := range deps.kotlinPlugins {
+ kotlincFlags = append(kotlincFlags, "-Xplugin="+plugin.String())
+ }
+ flags.kotlincDeps = append(flags.kotlincDeps, deps.kotlinPlugins...)
+
if len(kotlincFlags) > 0 {
// optimization.
ctx.Variable(pctx, "kotlincFlags", strings.Join(kotlincFlags, " "))
@@ -916,6 +1107,8 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
flags.classpath = append(flags.classpath, deps.kotlinStdlib...)
flags.classpath = append(flags.classpath, deps.kotlinAnnotations...)
+ flags.dexClasspath = append(flags.dexClasspath, deps.kotlinAnnotations...)
+
flags.kotlincClasspath = append(flags.kotlincClasspath, flags.bootClasspath...)
flags.kotlincClasspath = append(flags.kotlincClasspath, flags.classpath...)
@@ -932,18 +1125,24 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
}
kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName)
- kotlinCompile(ctx, kotlinJar, kotlinSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
+ kotlinHeaderJar := android.PathForModuleOut(ctx, "kotlin_headers", jarName)
+ kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, kotlinSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
if ctx.Failed() {
return
}
// Make javac rule depend on the kotlinc rule
- flags.classpath = append(flags.classpath, kotlinJar)
+ flags.classpath = append(classpath{kotlinHeaderJar}, flags.classpath...)
kotlinJars = append(kotlinJars, kotlinJar)
+ kotlinHeaderJars = append(kotlinHeaderJars, kotlinHeaderJar)
+
// Jar kotlin classes into the final jar after javac
if BoolDefault(j.properties.Static_kotlin_stdlib, true) {
kotlinJars = append(kotlinJars, deps.kotlinStdlib...)
+ kotlinHeaderJars = append(kotlinHeaderJars, deps.kotlinStdlib...)
+ } else {
+ flags.dexClasspath = append(flags.dexClasspath, deps.kotlinStdlib...)
}
}
@@ -954,8 +1153,8 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
j.compiledSrcJars = srcJars
enableSharding := false
- var headerJarFileWithoutJarjar android.Path
- if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !deps.disableTurbine {
+ var headerJarFileWithoutDepsOrJarjar android.Path
+ if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !disableTurbine {
if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 {
enableSharding = true
// Formerly, there was a check here that prevented annotation processors
@@ -964,27 +1163,38 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
// allow for the use of annotation processors that do function correctly
// with sharding enabled. See: b/77284273.
}
- headerJarFileWithoutJarjar, j.headerJarFile =
- j.compileJavaHeader(ctx, uniqueSrcFiles, srcJars, deps, flags, jarName, kotlinJars)
+ headerJarFileWithoutDepsOrJarjar, j.headerJarFile =
+ j.compileJavaHeader(ctx, uniqueSrcFiles, srcJars, deps, flags, jarName, kotlinHeaderJars)
if ctx.Failed() {
return
}
}
if len(uniqueSrcFiles) > 0 || len(srcJars) > 0 {
var extraJarDeps android.Paths
- if ctx.Config().RunErrorProne() {
- // If error-prone is enabled, add an additional rule to compile the java files into
- // a separate set of classes (so that they don't overwrite the normal ones and require
- // a rebuild when error-prone is turned off).
- // TODO(ccross): Once we always compile with javac9 we may be able to conditionally
- // enable error-prone without affecting the output class files.
+ if Bool(j.properties.Errorprone.Enabled) {
+ // If error-prone is enabled, enable errorprone flags on the regular
+ // build.
+ flags = enableErrorproneFlags(flags)
+ } else if ctx.Config().RunErrorProne() && j.properties.Errorprone.Enabled == nil {
+ // Otherwise, if the RUN_ERROR_PRONE environment variable is set, create
+ // a new jar file just for compiling with the errorprone compiler to.
+ // This is because we don't want to cause the java files to get completely
+ // rebuilt every time the state of the RUN_ERROR_PRONE variable changes.
+ // We also don't want to run this if errorprone is enabled by default for
+ // this module, or else we could have duplicated errorprone messages.
+ errorproneFlags := enableErrorproneFlags(flags)
errorprone := android.PathForModuleOut(ctx, "errorprone", jarName)
- RunErrorProne(ctx, errorprone, uniqueSrcFiles, srcJars, flags)
+
+ transformJavaToClasses(ctx, errorprone, -1, uniqueSrcFiles, srcJars, errorproneFlags, nil,
+ "errorprone", "errorprone")
+
extraJarDeps = append(extraJarDeps, errorprone)
}
if enableSharding {
- flags.classpath = append(flags.classpath, headerJarFileWithoutJarjar)
+ if headerJarFileWithoutDepsOrJarjar != nil {
+ flags.classpath = append(classpath{headerJarFileWithoutDepsOrJarjar}, flags.classpath...)
+ }
shardSize := int(*(j.properties.Javac_shard_size))
var shardSrcs []android.Paths
if len(uniqueSrcFiles) > 0 {
@@ -1152,10 +1362,25 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
// Check package restrictions if necessary.
if len(j.properties.Permitted_packages) > 0 {
- // Check packages and copy to package-checked file.
+ // Time stamp file created by the package check rule.
pkgckFile := android.PathForModuleOut(ctx, "package-check.stamp")
+
+ // Create a rule to copy the output jar to another path and add a validate dependency that
+ // will check that the jar only contains the permitted packages. The new location will become
+ // the output file of this module.
+ inputFile := outputFile
+ outputFile = android.PathForModuleOut(ctx, "package-check", jarName).OutputPath
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: inputFile,
+ Output: outputFile,
+ // Make sure that any dependency on the output file will cause ninja to run the package check
+ // rule.
+ Validation: pkgckFile,
+ })
+
+ // Check packages and create a timestamp file when complete.
CheckJarPackages(ctx, pkgckFile, outputFile, j.properties.Permitted_packages)
- j.additionalCheckedModules = append(j.additionalCheckedModules, pkgckFile)
if ctx.Failed() {
return
@@ -1212,7 +1437,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
}
// Dex compilation
var dexOutputFile android.OutputPath
- dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(ctx), outputFile, jarName)
+ dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(ctx), implementationAndResourcesJar, jarName)
if ctx.Failed() {
return
}
@@ -1233,12 +1458,13 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
}
// Initialize the hiddenapi structure.
- j.initHiddenAPI(ctx, dexOutputFile, j.implementationJarFile, j.dexProperties.Uncompress_dex)
+
+ j.initHiddenAPI(ctx, makeDexJarPathFromPath(dexOutputFile), j.implementationJarFile, j.dexProperties.Uncompress_dex)
// Encode hidden API flags in dex file, if needed.
dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile)
- j.dexJarFile = dexOutputFile
+ j.dexJarFile = makeDexJarPathFromPath(dexOutputFile)
// Dexpreopting
j.dexpreopt(ctx, dexOutputFile)
@@ -1248,7 +1474,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
// There is no code to compile into a dex jar, make sure the resources are propagated
// to the APK if this is an app.
outputFile = implementationAndResourcesJar
- j.dexJarFile = j.resourceJar
+ j.dexJarFile = makeDexJarPathFromPath(j.resourceJar)
}
if ctx.Failed() {
@@ -1259,11 +1485,11 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
}
if ctx.Device() {
- lintSDKVersionString := func(sdkSpec android.SdkSpec) string {
+ lintSDKVersion := func(sdkSpec android.SdkSpec) android.ApiLevel {
if v := sdkSpec.ApiLevel; !v.IsPreview() {
- return v.String()
+ return v
} else {
- return ctx.Config().DefaultAppTargetSdk(ctx).String()
+ return ctx.Config().DefaultAppTargetSdk(ctx)
}
}
@@ -1272,9 +1498,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
j.linter.srcJars = srcJars
j.linter.classpath = append(append(android.Paths(nil), flags.bootClasspath...), flags.classpath...)
j.linter.classes = j.implementationJarFile
- j.linter.minSdkVersion = lintSDKVersionString(j.MinSdkVersion(ctx))
- j.linter.targetSdkVersion = lintSDKVersionString(j.TargetSdkVersion(ctx))
- j.linter.compileSdkVersion = lintSDKVersionString(j.SdkVersion(ctx))
+ j.linter.minSdkVersion = lintSDKVersion(j.MinSdkVersion(ctx))
+ j.linter.targetSdkVersion = lintSDKVersion(j.TargetSdkVersion(ctx))
+ j.linter.compileSdkVersion = lintSDKVersion(j.SdkVersion(ctx))
j.linter.compileSdkKind = j.SdkVersion(ctx).Kind
j.linter.javaLanguageLevel = flags.javaVersion.String()
j.linter.kotlinLanguageLevel = "1.3"
@@ -1304,6 +1530,25 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
j.outputFile = outputFile.WithoutRel()
}
+func (j *Module) useCompose() bool {
+ return android.InList("androidx.compose.runtime_runtime", j.properties.Static_libs)
+}
+
+// Returns a copy of the supplied flags, but with all the errorprone-related
+// fields copied to the regular build's fields.
+func enableErrorproneFlags(flags javaBuilderFlags) javaBuilderFlags {
+ flags.processorPath = append(flags.errorProneProcessorPath, flags.processorPath...)
+
+ if len(flags.errorProneExtraJavacFlags) > 0 {
+ if len(flags.javacFlags) > 0 {
+ flags.javacFlags += " " + flags.errorProneExtraJavacFlags
+ } else {
+ flags.javacFlags = flags.errorProneExtraJavacFlags
+ }
+ }
+ return flags
+}
+
func (j *Module) compileJavaClasses(ctx android.ModuleContext, jarName string, idx int,
srcFiles, srcJars android.Paths, flags javaBuilderFlags, extraJarDeps android.Paths) android.WritablePath {
@@ -1352,7 +1597,7 @@ func CheckKotlincFlags(ctx android.ModuleContext, flags []string) {
func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths,
deps deps, flags javaBuilderFlags, jarName string,
- extraJars android.Paths) (headerJar, jarjarHeaderJar android.Path) {
+ extraJars android.Paths) (headerJar, jarjarAndDepsHeaderJar android.Path) {
var jars android.Paths
if len(srcFiles) > 0 || len(srcJars) > 0 {
@@ -1363,6 +1608,7 @@ func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars
return nil, nil
}
jars = append(jars, turbineJar)
+ headerJar = turbineJar
}
jars = append(jars, extraJars...)
@@ -1376,20 +1622,19 @@ func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars
combinedJar := android.PathForModuleOut(ctx, "turbine-combined", jarName)
TransformJarsToJar(ctx, combinedJar, "for turbine", jars, android.OptionalPath{},
false, nil, []string{"META-INF/TRANSITIVE"})
- headerJar = combinedJar
- jarjarHeaderJar = combinedJar
+ jarjarAndDepsHeaderJar = combinedJar
if j.expandJarjarRules != nil {
// Transform classes.jar into classes-jarjar.jar
jarjarFile := android.PathForModuleOut(ctx, "turbine-jarjar", jarName)
- TransformJarJar(ctx, jarjarFile, headerJar, j.expandJarjarRules)
- jarjarHeaderJar = jarjarFile
+ TransformJarJar(ctx, jarjarFile, jarjarAndDepsHeaderJar, j.expandJarjarRules)
+ jarjarAndDepsHeaderJar = jarjarFile
if ctx.Failed() {
return nil, nil
}
}
- return headerJar, jarjarHeaderJar
+ return headerJar, jarjarAndDepsHeaderJar
}
func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
@@ -1419,7 +1664,7 @@ func (j *Module) ImplementationJars() android.Paths {
return android.Paths{j.implementationJarFile}
}
-func (j *Module) DexJarBuildPath() android.Path {
+func (j *Module) DexJarBuildPath() OptionalDexJarPath {
return j.dexJarFile
}
@@ -1453,6 +1698,8 @@ func (j *Module) IDEInfo(dpInfo *android.IdeInfo) {
dpInfo.Jarjar_rules = append(dpInfo.Jarjar_rules, j.expandJarjarRules.String())
}
dpInfo.Paths = append(dpInfo.Paths, j.modulePaths...)
+ dpInfo.Static_libs = append(dpInfo.Static_libs, j.properties.Static_libs...)
+ dpInfo.Libs = append(dpInfo.Libs, j.properties.Libs...)
}
func (j *Module) CompilerDeps() []string {
@@ -1473,8 +1720,7 @@ func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu
}
// Implements android.ApexModule
-func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
- sdkVersion android.ApiLevel) error {
+func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
sdkSpec := j.MinSdkVersion(ctx)
if !sdkSpec.Specified() {
return fmt.Errorf("min_sdk_version is not specified")
@@ -1482,18 +1728,14 @@ func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
if sdkSpec.Kind == android.SdkCore {
return nil
}
- ver, err := sdkSpec.EffectiveVersion(ctx)
- if err != nil {
- return err
- }
- if ver.GreaterThan(sdkVersion) {
- return fmt.Errorf("newer SDK(%v)", ver)
+ if sdkSpec.ApiLevel.GreaterThan(sdkVersion) {
+ return fmt.Errorf("newer SDK(%v)", sdkSpec.ApiLevel)
}
return nil
}
func (j *Module) Stem() string {
- return proptools.StringDefault(j.deviceProperties.Stem, j.Name())
+ return proptools.StringDefault(j.overridableDeviceProperties.Stem, j.Name())
}
func (j *Module) JacocoReportClassesFile() android.Path {
@@ -1627,6 +1869,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
} else if sdkDep.useFiles {
// sdkDep.jar is actually equivalent to turbine header.jar.
deps.classpath = append(deps.classpath, sdkDep.jars...)
+ deps.dexClasspath = append(deps.dexClasspath, sdkDep.jars...)
deps.aidlPreprocess = sdkDep.aidl
} else {
deps.aidlPreprocess = sdkDep.aidl
@@ -1651,7 +1894,9 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
if dep, ok := module.(SdkLibraryDependency); ok {
switch tag {
case libTag:
- deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...)
+ depHeaderJars := dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))
+ deps.classpath = append(deps.classpath, depHeaderJars...)
+ deps.dexClasspath = append(deps.dexClasspath, depHeaderJars...)
case staticLibTag:
ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
}
@@ -1670,6 +1915,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars...)
case libTag, instrumentationForTag:
deps.classpath = append(deps.classpath, dep.HeaderJars...)
+ deps.dexClasspath = append(deps.dexClasspath, dep.HeaderJars...)
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...)
deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine
@@ -1723,6 +1969,8 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars...)
case kotlinAnnotationsTag:
deps.kotlinAnnotations = dep.HeaderJars
+ case kotlinPluginTag:
+ deps.kotlinPlugins = append(deps.kotlinPlugins, dep.ImplementationAndResourcesJars...)
case syspropPublicStubDepTag:
// This is a sysprop implementation library, forward the JavaInfoProvider from
// the corresponding sysprop public stub library as SyspropPublicStubInfoProvider.
@@ -1735,6 +1983,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
case libTag:
checkProducesJars(ctx, dep)
deps.classpath = append(deps.classpath, dep.Srcs()...)
+ deps.dexClasspath = append(deps.classpath, dep.Srcs()...)
case staticLibTag:
checkProducesJars(ctx, dep)
deps.classpath = append(deps.classpath, dep.Srcs()...)
@@ -1756,6 +2005,9 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
sm := module.(SystemModulesProvider)
outputDir, outputDeps := sm.OutputDirAndDeps()
deps.systemModules = &systemModules{outputDir, outputDeps}
+
+ case instrumentationForTag:
+ ctx.PropertyErrorf("instrumentation_for", "dependency %q of type %q does not provide JavaInfo so is unsuitable for use with this property", ctx.OtherModuleName(module), ctx.OtherModuleType(module))
}
}
@@ -1785,3 +2037,16 @@ type ModuleWithStem interface {
}
var _ ModuleWithStem = (*Module)(nil)
+
+func (j *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ switch ctx.ModuleType() {
+ case "java_library", "java_library_host", "java_library_static":
+ if lib, ok := ctx.Module().(*Library); ok {
+ javaLibraryBp2Build(ctx, lib)
+ }
+ case "java_binary_host":
+ if binary, ok := ctx.Module().(*Binary); ok {
+ javaBinaryHostBp2Build(ctx, binary)
+ }
+ }
+}
diff --git a/java/boot_jars.go b/java/boot_jars.go
index 86ebe36b4..5d40ec389 100644
--- a/java/boot_jars.go
+++ b/java/boot_jars.go
@@ -31,13 +31,18 @@ func isActiveModule(module android.Module) bool {
// buildRuleForBootJarsPackageCheck generates the build rule to perform the boot jars package
// check.
func buildRuleForBootJarsPackageCheck(ctx android.ModuleContext, bootDexJarByModule bootDexJarByModule) {
+ bootDexJars := bootDexJarByModule.bootDexJarsWithoutCoverage()
+ if len(bootDexJars) == 0 {
+ return
+ }
+
timestamp := android.PathForOutput(ctx, "boot-jars-package-check/stamp")
rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().BuiltTool("check_boot_jars").
Input(ctx.Config().HostToolPath(ctx, "dexdump")).
Input(android.PathForSource(ctx, "build/soong/scripts/check_boot_jars/package_allowed_list.txt")).
- Inputs(bootDexJarByModule.bootDexJarsWithoutCoverage()).
+ Inputs(bootDexJars).
Text("&& touch").Output(timestamp)
rule.Build("boot_jars_package_check", "check boot jar packages")
diff --git a/java/bootclasspath.go b/java/bootclasspath.go
index d754fe6aa..52ce77d46 100644
--- a/java/bootclasspath.go
+++ b/java/bootclasspath.go
@@ -95,15 +95,6 @@ func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex st
if ctx.OtherModuleDependencyVariantExists(variations, prebuiltName) {
ctx.AddVariationDependencies(variations, tag, prebuiltName)
addedDep = true
- } else if ctx.Config().AlwaysUsePrebuiltSdks() && len(variations) > 0 {
- // TODO(b/179354495): Remove this code path once the Android build has been fully migrated to
- // use bootclasspath_fragment properly.
- // Some prebuilt java_sdk_library modules do not yet have an APEX variations so try and add a
- // dependency on the non-APEX variant.
- if ctx.OtherModuleDependencyVariantExists(nil, prebuiltName) {
- ctx.AddVariationDependencies(nil, tag, prebuiltName)
- addedDep = true
- }
}
// If no appropriate variant existing for this, so no dependency could be added, then it is an
@@ -144,6 +135,8 @@ func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tag blueprin
// ApexVariantReference specifies a particular apex variant of a module.
type ApexVariantReference struct {
+ android.BpPrintableBase
+
// The name of the module apex variant, i.e. the apex containing the module variant.
//
// If this is not specified then it defaults to "platform" which will cause a dependency to be
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index a0399645f..96009351f 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -16,6 +16,7 @@ package java
import (
"fmt"
+ "io"
"path/filepath"
"reflect"
"strings"
@@ -89,7 +90,7 @@ var bootclasspathFragmentContentDepTag = bootclasspathFragmentContentDependencyT
var _ android.ExcludeFromVisibilityEnforcementTag = bootclasspathFragmentContentDepTag
var _ android.ReplaceSourceWithPrebuilt = bootclasspathFragmentContentDepTag
-var _ android.SdkMemberTypeDependencyTag = bootclasspathFragmentContentDepTag
+var _ android.SdkMemberDependencyTag = bootclasspathFragmentContentDepTag
var _ android.CopyDirectlyInAnyApexTag = bootclasspathFragmentContentDepTag
var _ android.RequiresFilesFromPrebuiltApexTag = bootclasspathFragmentContentDepTag
@@ -139,6 +140,87 @@ type bootclasspathFragmentProperties struct {
BootclasspathFragmentsDepsProperties
}
+type HiddenApiPackageProperties struct {
+ Hidden_api struct {
+ // Contains prefixes of a package hierarchy that is provided solely by this
+ // bootclasspath_fragment.
+ //
+ // This affects the signature patterns file that is used to select the subset of monolithic
+ // hidden API flags. See split_packages property for more details.
+ Package_prefixes []string
+
+ // A list of individual packages that are provided solely by this
+ // bootclasspath_fragment but which cannot be listed in package_prefixes
+ // because there are sub-packages which are provided by other modules.
+ //
+ // This should only be used for legacy packages. New packages should be
+ // covered by a package prefix.
+ Single_packages []string
+
+ // The list of split packages provided by this bootclasspath_fragment.
+ //
+ // A split package is one that contains classes which are provided by multiple
+ // bootclasspath_fragment modules.
+ //
+ // This defaults to "*" - which treats all packages as being split. A module that has no split
+ // packages must specify an empty list.
+ //
+ // This affects the signature patterns file that is generated by a bootclasspath_fragment and
+ // used to select the subset of monolithic hidden API flags against which the flags generated
+ // by the bootclasspath_fragment are compared.
+ //
+ // The signature patterns file selects the subset of monolithic hidden API flags using a number
+ // of patterns, i.e.:
+ // * The qualified name (including package) of an outermost class, e.g. java/lang/Character.
+ // This selects all the flags for all the members of this class and any nested classes.
+ // * A package wildcard, e.g. java/lang/*. This selects all the flags for all the members of all
+ // the classes in this package (but not in sub-packages).
+ // * A recursive package wildcard, e.g. java/**. This selects all the flags for all the members
+ // of all the classes in this package and sub-packages.
+ //
+ // The signature patterns file is constructed as follows:
+ // * All the signatures are retrieved from the all-flags.csv file.
+ // * The member and inner class names are removed.
+ // * If a class is in a split package then that is kept, otherwise the class part is removed
+ // and replaced with a wildcard, i.e. *.
+ // * If a package matches a package prefix then the package is removed.
+ // * All the package prefixes are added with a recursive wildcard appended to each, i.e. **.
+ // * The resulting patterns are sorted.
+ //
+ // So, by default (i.e. without specifying any package_prefixes or split_packages) the signature
+ // patterns is a list of class names, because there are no package packages and all packages are
+ // assumed to be split.
+ //
+ // If any split packages are specified then only those packages are treated as split and all
+ // other packages are treated as belonging solely to the bootclasspath_fragment and so they use
+ // wildcard package patterns.
+ //
+ // So, if an empty list of split packages is specified then the signature patterns file just
+ // includes a wildcard package pattern for every package provided by the bootclasspath_fragment.
+ //
+ // If split_packages are specified and a package that is split is not listed then it could lead
+ // to build failures as it will select monolithic flags that are generated by another
+ // bootclasspath_fragment to compare against the flags provided by this fragment. The latter
+ // will obviously not contain those flags and that can cause the comparison and build to fail.
+ //
+ // If any package prefixes are specified then any matching packages are removed from the
+ // signature patterns and replaced with a single recursive package pattern.
+ //
+ // It is not strictly necessary to specify either package_prefixes or split_packages as the
+ // defaults will produce a valid set of signature patterns. However, those patterns may include
+ // implementation details, e.g. names of implementation classes or packages, which will be
+ // exported to the sdk snapshot in the signature patterns file. That is something that should be
+ // avoided where possible. Specifying package_prefixes and split_packages allows those
+ // implementation details to be excluded from the snapshot.
+ Split_packages []string
+ }
+}
+
+type SourceOnlyBootclasspathProperties struct {
+ HiddenApiPackageProperties
+ Coverage HiddenApiPackageProperties
+}
+
type BootclasspathFragmentModule struct {
android.ModuleBase
android.ApexModuleBase
@@ -146,6 +228,16 @@ type BootclasspathFragmentModule struct {
ClasspathFragmentBase
properties bootclasspathFragmentProperties
+
+ sourceOnlyProperties SourceOnlyBootclasspathProperties
+
+ // Collect the module directory for IDE info in java/jdeps.go.
+ modulePaths []string
+
+ // Installs for on-device boot image files. This list has entries only if the installs should be
+ // handled by Make (e.g., the boot image should be installed on the system partition, rather than
+ // in the APEX).
+ bootImageDeviceInstalls []dexpreopterInstall
}
// commonBootclasspathFragment defines the methods that are implemented by both source and prebuilt
@@ -177,7 +269,7 @@ type bootImageFilesByArch map[android.ArchType]android.Paths
func bootclasspathFragmentFactory() android.Module {
m := &BootclasspathFragmentModule{}
- m.AddProperties(&m.properties)
+ m.AddProperties(&m.properties, &m.sourceOnlyProperties)
android.InitApexModule(m)
android.InitSdkAwareModule(m)
initClasspathFragment(m, BOOTCLASSPATH)
@@ -192,6 +284,12 @@ func bootclasspathFragmentFactory() android.Module {
ctx.PropertyErrorf("coverage", "error trying to append coverage specific properties: %s", err)
return
}
+
+ err = proptools.AppendProperties(&m.sourceOnlyProperties.HiddenApiPackageProperties, &m.sourceOnlyProperties.Coverage, nil)
+ if err != nil {
+ ctx.PropertyErrorf("coverage", "error trying to append hidden api coverage specific properties: %s", err)
+ return
+ }
}
// Initialize the contents property from the image_name.
@@ -314,9 +412,19 @@ type BootclasspathFragmentApexContentInfo struct {
// Map from arch type to the boot image files.
bootImageFilesByArch bootImageFilesByArch
+ // True if the boot image should be installed in the APEX.
+ shouldInstallBootImageInApex bool
+
// Map from the base module name (without prebuilt_ prefix) of a fragment's contents module to the
// hidden API encoded dex jar path.
contentModuleDexJarPaths bootDexJarByModule
+
+ // Path to the image profile file on host (or empty, if profile is not generated).
+ profilePathOnHost android.Path
+
+ // Install path of the boot image profile if it needs to be installed in the APEX, or empty if not
+ // needed.
+ profileInstallPathInApex string
}
func (i BootclasspathFragmentApexContentInfo) Modules() android.ConfiguredJarList {
@@ -330,6 +438,11 @@ func (i BootclasspathFragmentApexContentInfo) AndroidBootImageFilesByArchType()
return i.bootImageFilesByArch
}
+// Return true if the boot image should be installed in the APEX.
+func (i *BootclasspathFragmentApexContentInfo) ShouldInstallBootImageInApex() bool {
+ return i.shouldInstallBootImageInApex
+}
+
// DexBootJarPathForContentModule returns the path to the dex boot jar for specified module.
//
// The dex boot jar is one which has had hidden API encoding performed on it.
@@ -345,6 +458,14 @@ func (i BootclasspathFragmentApexContentInfo) DexBootJarPathForContentModule(mod
}
}
+func (i BootclasspathFragmentApexContentInfo) ProfilePathOnHost() android.Path {
+ return i.profilePathOnHost
+}
+
+func (i BootclasspathFragmentApexContentInfo) ProfileInstallPathInApex() string {
+ return i.profileInstallPathInApex
+}
+
func (b *BootclasspathFragmentModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
tag := ctx.OtherModuleDependencyTag(dep)
if IsBootclasspathFragmentContentDepTag(tag) {
@@ -422,6 +543,9 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo
// Generate classpaths.proto config
b.generateClasspathProtoBuildActions(ctx)
+ // Collect the module directory for IDE info in java/jdeps.go.
+ b.modulePaths = append(b.modulePaths, ctx.ModuleDir())
+
// Gather the bootclasspath fragment's contents.
var contents []android.Module
ctx.VisitDirectDeps(func(module android.Module) {
@@ -459,6 +583,24 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo
// Copy the dex jars of this fragment's content modules to their predefined locations.
copyBootJarsToPredefinedLocations(ctx, hiddenAPIOutput.EncodedBootDexFilesByModule, imageConfig.dexPathsByModule)
}
+
+ for _, variant := range imageConfig.apexVariants() {
+ arch := variant.target.Arch.ArchType.String()
+ for _, install := range variant.deviceInstalls {
+ // Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
+ installDir := strings.TrimPrefix(filepath.Dir(install.To), "/")
+ installBase := filepath.Base(install.To)
+ installPath := android.PathForModuleInPartitionInstall(ctx, "", installDir)
+
+ b.bootImageDeviceInstalls = append(b.bootImageDeviceInstalls, dexpreopterInstall{
+ name: arch + "-" + installBase,
+ moduleName: b.Name(),
+ outputPathOnHost: install.From,
+ installDirOnDevice: installPath,
+ installFileOnDevice: installBase,
+ })
+ }
+ }
}
// A prebuilt fragment cannot contribute to an apex.
@@ -466,6 +608,19 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo
// Provide the apex content info.
b.provideApexContentInfo(ctx, imageConfig, hiddenAPIOutput, bootImageFilesByArch)
}
+ } else {
+ // Versioned fragments are not needed by make.
+ b.HideFromMake()
+ }
+
+ // In order for information about bootclasspath_fragment modules to be added to module-info.json
+ // it is necessary to output an entry to Make. As bootclasspath_fragment modules are part of an
+ // APEX there can be multiple variants, including the default/platform variant and only one can
+ // be output to Make but it does not really matter which variant is output. The default/platform
+ // variant is the first (ctx.PrimaryModule()) and is usually hidden from make so this just picks
+ // the last variant (ctx.FinalModule()).
+ if ctx.Module() != ctx.FinalModule() {
+ b.HideFromMake()
}
}
@@ -503,6 +658,13 @@ func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleC
if imageConfig != nil {
info.modules = imageConfig.modules
+ global := dexpreopt.GetGlobalConfig(ctx)
+ if !global.DisableGenerateProfile {
+ info.profilePathOnHost = imageConfig.profilePathOnHost
+ info.profileInstallPathInApex = imageConfig.profileInstallPathInApex
+ }
+
+ info.shouldInstallBootImageInApex = imageConfig.shouldInstallInApex()
}
info.bootImageFilesByArch = bootImageFilesByArch
@@ -514,35 +676,46 @@ func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleC
// generateClasspathProtoBuildActions generates all required build actions for classpath.proto config
func (b *BootclasspathFragmentModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) {
var classpathJars []classpathJar
+ configuredJars := b.configuredJars(ctx)
if "art" == proptools.String(b.properties.Image_name) {
// ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH
- classpathJars = configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), BOOTCLASSPATH, DEX2OATBOOTCLASSPATH)
+ classpathJars = configuredJarListToClasspathJars(ctx, configuredJars, BOOTCLASSPATH, DEX2OATBOOTCLASSPATH)
} else {
- classpathJars = configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), b.classpathType)
+ classpathJars = configuredJarListToClasspathJars(ctx, configuredJars, b.classpathType)
}
- b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, classpathJars)
+ b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars)
}
-func (b *BootclasspathFragmentModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
+func (b *BootclasspathFragmentModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList {
if "art" == proptools.String(b.properties.Image_name) {
return b.getImageConfig(ctx).modules
}
global := dexpreopt.GetGlobalConfig(ctx)
- possibleUpdatableModules := gatherPossibleUpdatableModuleNamesAndStems(ctx, b.properties.Contents, bootclasspathFragmentContentDepTag)
-
- // Only create configs for updatable boot jars. Non-updatable boot jars must be part of the
- // platform_bootclasspath's classpath proto config to guarantee that they come before any
- // updatable jars at runtime.
- jars := global.UpdatableBootJars.Filter(possibleUpdatableModules)
+ possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, b.properties.Contents, bootclasspathFragmentContentDepTag)
+ jars, unknown := global.ApexBootJars.Filter(possibleUpdatableModules)
// TODO(satayev): for apex_test we want to include all contents unconditionally to classpaths
- // config. However, any test specific jars would not be present in UpdatableBootJars. Instead,
+ // config. However, any test specific jars would not be present in ApexBootJars. Instead,
// we should check if we are creating a config for apex_test via ApexInfo and amend the values.
// This is an exception to support end-to-end test for SdkExtensions, until such support exists.
if android.InList("test_framework-sdkextensions", possibleUpdatableModules) {
jars = jars.Append("com.android.sdkext", "test_framework-sdkextensions")
+ } else if android.InList("AddNewActivity", possibleUpdatableModules) {
+ jars = jars.Append("test_com.android.cts.frameworkresapkplits", "AddNewActivity")
+ } else if android.InList("test_framework-apexd", possibleUpdatableModules) {
+ jars = jars.Append("com.android.apex.test_package", "test_framework-apexd")
+ } else if global.ApexBootJars.Len() != 0 && !android.IsModuleInVersionedSdk(ctx.Module()) {
+ unknown = android.RemoveListFromList(unknown, b.properties.Coverage.Contents)
+ _, unknown = android.RemoveFromList("core-icu4j", unknown)
+ // This module only exists in car products.
+ // So ignore it even if it is not in PRODUCT_APEX_BOOT_JARS.
+ // TODO(b/202896428): Add better way to handle this.
+ _, unknown = android.RemoveFromList("android.car-module", unknown)
+ if len(unknown) > 0 {
+ ctx.ModuleErrorf("%s in contents must also be declared in PRODUCT_APEX_BOOT_JARS", unknown)
+ }
}
return jars
}
@@ -576,6 +749,15 @@ func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.
common := ctx.Module().(commonBootclasspathFragment)
output := common.produceHiddenAPIOutput(ctx, contents, input)
+ // If the source or prebuilts module does not provide a signature patterns file then generate one
+ // from the flags.
+ // TODO(b/192868581): Remove once the source and prebuilts provide a signature patterns file of
+ // their own.
+ if output.SignaturePatternsPath == nil {
+ output.SignaturePatternsPath = buildRuleSignaturePatternsFile(
+ ctx, output.AllFlagsPath, []string{"*"}, nil, nil)
+ }
+
// Initialize a HiddenAPIInfo structure.
hiddenAPIInfo := HiddenAPIInfo{
// The monolithic hidden API processing needs access to the flag files that override the default
@@ -592,7 +774,7 @@ func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.
// The monolithic hidden API processing also needs access to all the output files produced by
// hidden API processing of this fragment.
- hiddenAPIInfo.HiddenAPIFlagOutput = (*output).HiddenAPIFlagOutput
+ hiddenAPIInfo.HiddenAPIFlagOutput = output.HiddenAPIFlagOutput
// Provide it for use by other modules.
ctx.SetProvider(HiddenAPIInfoProvider, hiddenAPIInfo)
@@ -642,7 +824,22 @@ func (b *BootclasspathFragmentModule) createHiddenAPIFlagInput(ctx android.Modul
func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
// Generate the rules to create the hidden API flags and update the supplied hiddenAPIInfo with the
// paths to the created files.
- return hiddenAPIRulesForBootclasspathFragment(ctx, contents, input)
+ output := hiddenAPIRulesForBootclasspathFragment(ctx, contents, input)
+
+ // If the module specifies split_packages or package_prefixes then use those to generate the
+ // signature patterns.
+ splitPackages := b.sourceOnlyProperties.Hidden_api.Split_packages
+ packagePrefixes := b.sourceOnlyProperties.Hidden_api.Package_prefixes
+ singlePackages := b.sourceOnlyProperties.Hidden_api.Single_packages
+ if splitPackages != nil || packagePrefixes != nil || singlePackages != nil {
+ if splitPackages == nil {
+ splitPackages = []string{"*"}
+ }
+ output.SignaturePatternsPath = buildRuleSignaturePatternsFile(
+ ctx, output.AllFlagsPath, splitPackages, packagePrefixes, singlePackages)
+ }
+
+ return output
}
// produceBootImageFiles builds the boot image files from the source if it is required.
@@ -691,12 +888,50 @@ func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android.
return androidBootImageFilesByArch
}
+func (b *BootclasspathFragmentModule) AndroidMkEntries() []android.AndroidMkEntries {
+ // Use the generated classpath proto as the output.
+ outputFile := b.outputFilepath
+ // Create a fake entry that will cause this to be added to the module-info.json file.
+ entriesList := []android.AndroidMkEntries{{
+ Class: "FAKE",
+ OutputFile: android.OptionalPathForPath(outputFile),
+ Include: "$(BUILD_PHONY_PACKAGE)",
+ ExtraFooters: []android.AndroidMkExtraFootersFunc{
+ func(w io.Writer, name, prefix, moduleDir string) {
+ // Allow the bootclasspath_fragment to be built by simply passing its name on the command
+ // line.
+ fmt.Fprintln(w, ".PHONY:", b.Name())
+ fmt.Fprintln(w, b.Name()+":", outputFile.String())
+ },
+ },
+ }}
+ for _, install := range b.bootImageDeviceInstalls {
+ entriesList = append(entriesList, install.ToMakeEntries())
+ }
+ return entriesList
+}
+
+// Returns the names of all Make modules that handle the installation of the boot image.
+func (b *BootclasspathFragmentModule) BootImageDeviceInstallMakeModules() []string {
+ var makeModules []string
+ for _, install := range b.bootImageDeviceInstalls {
+ makeModules = append(makeModules, install.FullModuleName())
+ }
+ return makeModules
+}
+
+// Collect information for opening IDE project files in java/jdeps.go.
+func (b *BootclasspathFragmentModule) IDEInfo(dpInfo *android.IdeInfo) {
+ dpInfo.Deps = append(dpInfo.Deps, b.properties.Contents...)
+ dpInfo.Paths = append(dpInfo.Paths, b.modulePaths...)
+}
+
type bootclasspathFragmentMemberType struct {
android.SdkMemberTypeBase
}
-func (b *bootclasspathFragmentMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
- mctx.AddVariationDependencies(nil, dependencyTag, names...)
+func (b *bootclasspathFragmentMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ ctx.AddVariationDependencies(nil, dependencyTag, names...)
}
func (b *bootclasspathFragmentMemberType) IsInstance(module android.Module) bool {
@@ -729,12 +964,12 @@ type bootclasspathFragmentSdkMemberProperties struct {
Stub_libs []string
Core_platform_stub_libs []string
+ // Fragment properties
+ Fragments []ApexVariantReference
+
// Flag files by *hiddenAPIFlagFileCategory
Flag_files_by_category FlagFilesByCategory
- // The path to the generated stub-flags.csv file.
- Stub_flags_path android.OptionalPath
-
// The path to the generated annotation-flags.csv file.
Annotation_flags_path android.OptionalPath
@@ -744,8 +979,20 @@ type bootclasspathFragmentSdkMemberProperties struct {
// The path to the generated index.csv file.
Index_path android.OptionalPath
+ // The path to the generated stub-flags.csv file.
+ Stub_flags_path android.OptionalPath `supported_build_releases:"S"`
+
// The path to the generated all-flags.csv file.
- All_flags_path android.OptionalPath
+ All_flags_path android.OptionalPath `supported_build_releases:"S"`
+
+ // The path to the generated signature-patterns.csv file.
+ Signature_patterns_path android.OptionalPath `supported_build_releases:"Tiramisu+"`
+
+ // The path to the generated filtered-stub-flags.csv file.
+ Filtered_stub_flags_path android.OptionalPath `supported_build_releases:"Tiramisu+"`
+
+ // The path to the generated filtered-flags.csv file.
+ Filtered_flags_path android.OptionalPath `supported_build_releases:"Tiramisu+"`
}
func (b *bootclasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
@@ -760,15 +1007,23 @@ func (b *bootclasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx andro
b.Flag_files_by_category = hiddenAPIInfo.FlagFilesByCategory
// Copy all the generated file paths.
- b.Stub_flags_path = android.OptionalPathForPath(hiddenAPIInfo.StubFlagsPath)
b.Annotation_flags_path = android.OptionalPathForPath(hiddenAPIInfo.AnnotationFlagsPath)
b.Metadata_path = android.OptionalPathForPath(hiddenAPIInfo.MetadataPath)
b.Index_path = android.OptionalPathForPath(hiddenAPIInfo.IndexPath)
+
+ b.Stub_flags_path = android.OptionalPathForPath(hiddenAPIInfo.StubFlagsPath)
b.All_flags_path = android.OptionalPathForPath(hiddenAPIInfo.AllFlagsPath)
+ b.Signature_patterns_path = android.OptionalPathForPath(hiddenAPIInfo.SignaturePatternsPath)
+ b.Filtered_stub_flags_path = android.OptionalPathForPath(hiddenAPIInfo.FilteredStubFlagsPath)
+ b.Filtered_flags_path = android.OptionalPathForPath(hiddenAPIInfo.FilteredFlagsPath)
+
// Copy stub_libs properties.
b.Stub_libs = module.properties.Api.Stub_libs
b.Core_platform_stub_libs = module.properties.Core_platform_api.Stub_libs
+
+ // Copy fragment properties.
+ b.Fragments = module.properties.Fragments
}
func (b *bootclasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
@@ -791,6 +1046,9 @@ func (b *bootclasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android.
corePlatformApiPropertySet := propertySet.AddPropertySet("core_platform_api")
corePlatformApiPropertySet.AddPropertyWithTag("stub_libs", b.Core_platform_stub_libs, requiredMemberDependency)
}
+ if len(b.Fragments) > 0 {
+ propertySet.AddProperty("fragments", b.Fragments)
+ }
hiddenAPISet := propertySet.AddPropertySet("hidden_api")
hiddenAPIDir := "hiddenapi"
@@ -821,11 +1079,16 @@ func (b *bootclasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android.
}
// Copy all the generated files, if available.
- copyOptionalPath(b.Stub_flags_path, "stub_flags")
copyOptionalPath(b.Annotation_flags_path, "annotation_flags")
copyOptionalPath(b.Metadata_path, "metadata")
copyOptionalPath(b.Index_path, "index")
+
+ copyOptionalPath(b.Stub_flags_path, "stub_flags")
copyOptionalPath(b.All_flags_path, "all_flags")
+
+ copyOptionalPath(b.Signature_patterns_path, "signature_patterns")
+ copyOptionalPath(b.Filtered_stub_flags_path, "filtered_stub_flags")
+ copyOptionalPath(b.Filtered_flags_path, "filtered_flags")
}
var _ android.SdkMemberType = (*bootclasspathFragmentMemberType)(nil)
@@ -834,9 +1097,6 @@ var _ android.SdkMemberType = (*bootclasspathFragmentMemberType)(nil)
// specific properties.
type prebuiltBootclasspathFragmentProperties struct {
Hidden_api struct {
- // The path to the stub-flags.csv file created by the bootclasspath_fragment.
- Stub_flags *string `android:"path"`
-
// The path to the annotation-flags.csv file created by the bootclasspath_fragment.
Annotation_flags *string `android:"path"`
@@ -846,8 +1106,20 @@ type prebuiltBootclasspathFragmentProperties struct {
// The path to the index.csv file created by the bootclasspath_fragment.
Index *string `android:"path"`
+ // The path to the signature-patterns.csv file created by the bootclasspath_fragment.
+ Signature_patterns *string `android:"path"`
+
+ // The path to the stub-flags.csv file created by the bootclasspath_fragment.
+ Stub_flags *string `android:"path"`
+
// The path to the all-flags.csv file created by the bootclasspath_fragment.
All_flags *string `android:"path"`
+
+ // The path to the filtered-stub-flags.csv file created by the bootclasspath_fragment.
+ Filtered_stub_flags *string `android:"path"`
+
+ // The path to the filtered-flags.csv file created by the bootclasspath_fragment.
+ Filtered_flags *string `android:"path"`
}
}
@@ -856,7 +1128,7 @@ type prebuiltBootclasspathFragmentProperties struct {
// At the moment this is basically just a bootclasspath_fragment module that can be used as a
// prebuilt. Eventually as more functionality is migrated into the bootclasspath_fragment module
// type from the various singletons then this will diverge.
-type prebuiltBootclasspathFragmentModule struct {
+type PrebuiltBootclasspathFragmentModule struct {
BootclasspathFragmentModule
prebuilt android.Prebuilt
@@ -864,20 +1136,26 @@ type prebuiltBootclasspathFragmentModule struct {
prebuiltProperties prebuiltBootclasspathFragmentProperties
}
-func (module *prebuiltBootclasspathFragmentModule) Prebuilt() *android.Prebuilt {
+func (module *PrebuiltBootclasspathFragmentModule) Prebuilt() *android.Prebuilt {
return &module.prebuilt
}
-func (module *prebuiltBootclasspathFragmentModule) Name() string {
+func (module *PrebuiltBootclasspathFragmentModule) Name() string {
return module.prebuilt.Name(module.ModuleBase.Name())
}
// produceHiddenAPIOutput returns a path to the prebuilt all-flags.csv or nil if none is specified.
-func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
- pathForOptionalSrc := func(src *string) android.Path {
+func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
+ pathForOptionalSrc := func(src *string, defaultPath android.Path) android.Path {
if src == nil {
- // TODO(b/179354495): Fail if this is not provided once prebuilts have been updated.
- return nil
+ return defaultPath
+ }
+ return android.PathForModuleSrc(ctx, *src)
+ }
+ pathForSrc := func(property string, src *string) android.Path {
+ if src == nil {
+ ctx.PropertyErrorf(property, "is required but was not specified")
+ return android.PathForModuleSrc(ctx, "missing", property)
}
return android.PathForModuleSrc(ctx, *src)
}
@@ -888,76 +1166,83 @@ func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx an
output := HiddenAPIOutput{
HiddenAPIFlagOutput: HiddenAPIFlagOutput{
- StubFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Stub_flags),
- AnnotationFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Annotation_flags),
- MetadataPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Metadata),
- IndexPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Index),
- AllFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.All_flags),
+ AnnotationFlagsPath: pathForSrc("hidden_api.annotation_flags", module.prebuiltProperties.Hidden_api.Annotation_flags),
+ MetadataPath: pathForSrc("hidden_api.metadata", module.prebuiltProperties.Hidden_api.Metadata),
+ IndexPath: pathForSrc("hidden_api.index", module.prebuiltProperties.Hidden_api.Index),
+ SignaturePatternsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Signature_patterns, nil),
+ // TODO: Temporarily handle stub_flags/all_flags properties until prebuilts have been updated.
+ StubFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Stub_flags, nil),
+ AllFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.All_flags, nil),
},
+
EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
}
+ // TODO: Temporarily fallback to stub_flags/all_flags properties until prebuilts have been updated.
+ output.FilteredStubFlagsPath = pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Filtered_stub_flags, output.StubFlagsPath)
+ output.FilteredFlagsPath = pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Filtered_flags, output.AllFlagsPath)
+
return &output
}
// produceBootImageFiles extracts the boot image files from the APEX if available.
-func (module *prebuiltBootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageFilesByArch {
+func (module *PrebuiltBootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageFilesByArch {
if !shouldCopyBootFilesToPredefinedLocations(ctx, imageConfig) {
return nil
}
- var deapexerModule android.Module
- ctx.VisitDirectDeps(func(to android.Module) {
- tag := ctx.OtherModuleDependencyTag(to)
- // Save away the `deapexer` module on which this depends, if any.
- if tag == android.DeapexerTag {
- if deapexerModule != nil {
- ctx.ModuleErrorf("Ambiguous duplicate deapexer module dependencies %q and %q",
- deapexerModule.Name(), to.Name())
- }
- deapexerModule = to
- }
- })
-
- if deapexerModule == nil {
- // This should never happen as a variant for a prebuilt_apex is only created if the
- // deapexer module has been configured to export the dex implementation jar for this module.
- ctx.ModuleErrorf("internal error: module does not depend on a `deapexer` module")
- return nil
+ di := android.FindDeapexerProviderForModule(ctx)
+ if di == nil {
+ return nil // An error has been reported by FindDeapexerProviderForModule.
}
- di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo)
- files := bootImageFilesByArch{}
- for _, variant := range imageConfig.apexVariants() {
- arch := variant.target.Arch.ArchType
- for _, toPath := range variant.imagesDeps {
- apexRelativePath := apexRootRelativePathToBootImageFile(arch, toPath.Base())
- // Get the path to the file that the deapexer extracted from the prebuilt apex file.
- fromPath := di.PrebuiltExportPath(apexRelativePath)
-
- // Return the toPath as the calling code expects the paths in the returned map to be the
- // paths predefined in the bootImageConfig.
- files[arch] = append(files[arch], toPath)
-
- // Copy the file to the predefined location.
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Cp,
- Input: fromPath,
- Output: toPath,
- })
- }
+ profile := (android.WritablePath)(nil)
+ if imageConfig.profileInstallPathInApex != "" {
+ profile = di.PrebuiltExportPath(imageConfig.profileInstallPathInApex)
}
- // Build the boot image files for the host variants. These are built from the dex files provided
- // by the contents of this module as prebuilt versions of the host boot image files are not
- // available, i.e. there is no host specific prebuilt apex containing them. This has to be built
- // without a profile as the prebuilt modules do not provide a profile.
- buildBootImageVariantsForBuildOs(ctx, imageConfig, nil)
+ // Build the boot image files for the host variants. These are always built from the dex files
+ // provided by the contents of this module as prebuilt versions of the host boot image files are
+ // not available, i.e. there is no host specific prebuilt apex containing them. This has to be
+ // built without a profile as the prebuilt modules do not provide a profile.
+ buildBootImageVariantsForBuildOs(ctx, imageConfig, profile)
- return files
+ if imageConfig.shouldInstallInApex() {
+ // If the boot image files for the android variants are in the prebuilt apex, we must use those
+ // rather than building new ones because those boot image files are going to be used on device.
+ files := bootImageFilesByArch{}
+ for _, variant := range imageConfig.apexVariants() {
+ arch := variant.target.Arch.ArchType
+ for _, toPath := range variant.imagesDeps {
+ apexRelativePath := apexRootRelativePathToBootImageFile(arch, toPath.Base())
+ // Get the path to the file that the deapexer extracted from the prebuilt apex file.
+ fromPath := di.PrebuiltExportPath(apexRelativePath)
+
+ // Return the toPath as the calling code expects the paths in the returned map to be the
+ // paths predefined in the bootImageConfig.
+ files[arch] = append(files[arch], toPath)
+
+ // Copy the file to the predefined location.
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: fromPath,
+ Output: toPath,
+ })
+ }
+ }
+ return files
+ } else {
+ if profile == nil {
+ ctx.ModuleErrorf("Unable to produce boot image files: neither boot image files nor profiles exists in the prebuilt apex")
+ return nil
+ }
+ // Build boot image files for the android variants from the dex files provided by the contents
+ // of this module.
+ return buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile)
+ }
}
-var _ commonBootclasspathFragment = (*prebuiltBootclasspathFragmentModule)(nil)
+var _ commonBootclasspathFragment = (*PrebuiltBootclasspathFragmentModule)(nil)
// createBootImageTag creates the tag to uniquely identify the boot image file among all of the
// files that a module requires from the prebuilt .apex file.
@@ -971,16 +1256,22 @@ func createBootImageTag(arch android.ArchType, baseName string) string {
//
// If there is no image config associated with this fragment then it returns nil. Otherwise, it
// returns the files that are listed in the image config.
-func (module *prebuiltBootclasspathFragmentModule) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) []string {
+func (module *PrebuiltBootclasspathFragmentModule) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) []string {
imageConfig := module.getImageConfig(ctx)
if imageConfig != nil {
- // Add the boot image files, e.g. .art, .oat and .vdex files.
files := []string{}
- for _, variant := range imageConfig.apexVariants() {
- arch := variant.target.Arch.ArchType
- for _, path := range variant.imagesDeps.Paths() {
- base := path.Base()
- files = append(files, apexRootRelativePathToBootImageFile(arch, base))
+ if imageConfig.profileInstallPathInApex != "" {
+ // Add the boot image profile.
+ files = append(files, imageConfig.profileInstallPathInApex)
+ }
+ if imageConfig.shouldInstallInApex() {
+ // Add the boot image files, e.g. .art, .oat and .vdex files.
+ for _, variant := range imageConfig.apexVariants() {
+ arch := variant.target.Arch.ArchType
+ for _, path := range variant.imagesDeps.Paths() {
+ base := path.Base()
+ files = append(files, apexRootRelativePathToBootImageFile(arch, base))
+ }
}
}
return files
@@ -992,10 +1283,10 @@ func apexRootRelativePathToBootImageFile(arch android.ArchType, base string) str
return filepath.Join("javalib", arch.String(), base)
}
-var _ android.RequiredFilesFromPrebuiltApex = (*prebuiltBootclasspathFragmentModule)(nil)
+var _ android.RequiredFilesFromPrebuiltApex = (*PrebuiltBootclasspathFragmentModule)(nil)
func prebuiltBootclasspathFragmentFactory() android.Module {
- m := &prebuiltBootclasspathFragmentModule{}
+ m := &PrebuiltBootclasspathFragmentModule{}
m.AddProperties(&m.properties, &m.prebuiltProperties)
// This doesn't actually have any prebuilt files of its own so pass a placeholder for the srcs
// array.
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index 3d0e1558f..d3de675d8 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -164,6 +164,7 @@ func TestBootclasspathFragment_Coverage(t *testing.T) {
prepareForTestWithBootclasspathFragment,
PrepareForTestWithJavaSdkLibraryFiles,
FixtureWithLastReleaseApis("mysdklibrary", "mycoveragestubs"),
+ FixtureConfigureApexBootJars("someapex:mybootlib"),
prepareWithBp,
)
@@ -186,6 +187,7 @@ func TestBootclasspathFragment_StubLibs(t *testing.T) {
prepareForTestWithBootclasspathFragment,
PrepareForTestWithJavaSdkLibraryFiles,
FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary", "mycoreplatform"),
+ FixtureConfigureApexBootJars("someapex:mysdklibrary"),
).RunTestWithBp(t, `
bootclasspath_fragment {
name: "myfragment",
diff --git a/java/builder.go b/java/builder.go
index cde87310f..c0fadd42c 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -120,42 +120,39 @@ var (
"extractMatchingApks",
blueprint.RuleParams{
Command: `rm -rf "$out" && ` +
- `${config.ExtractApksCmd} -o "${out}" -allow-prereleased=${allow-prereleased} ` +
+ `${config.ExtractApksCmd} -o "${out}" -zip "${zip}" -allow-prereleased=${allow-prereleased} ` +
`-sdk-version=${sdk-version} -abis=${abis} ` +
`--screen-densities=${screen-densities} --stem=${stem} ` +
`-apkcerts=${apkcerts} -partition=${partition} ` +
`${in}`,
CommandDeps: []string{"${config.ExtractApksCmd}"},
},
- "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem", "apkcerts", "partition")
+ "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem", "apkcerts", "partition", "zip")
turbine, turbineRE = pctx.RemoteStaticRules("turbine",
blueprint.RuleParams{
- Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
- `$reTemplate${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.TurbineJar} --output $out.tmp ` +
- `--temp_dir "$outDir" --sources @$out.rsp --source_jars $srcJars ` +
+ Command: `$reTemplate${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.TurbineJar} $outputFlags ` +
+ `--sources @$out.rsp --source_jars $srcJars ` +
`--javacopts ${config.CommonJdkFlags} ` +
- `$javacFlags -source $javaVersion -target $javaVersion -- $bootClasspath $classpath && ` +
- `${config.Ziptime} $out.tmp && ` +
- `(if cmp -s $out.tmp $out ; then rm $out.tmp ; else mv $out.tmp $out ; fi )`,
+ `$javacFlags -source $javaVersion -target $javaVersion -- $turbineFlags && ` +
+ `(for o in $outputs; do if cmp -s $${o}.tmp $${o} ; then rm $${o}.tmp ; else mv $${o}.tmp $${o} ; fi; done )`,
CommandDeps: []string{
"${config.TurbineJar}",
"${config.JavaCmd}",
- "${config.Ziptime}",
},
Rspfile: "$out.rsp",
RspfileContent: "$in",
Restat: true,
},
&remoteexec.REParams{Labels: map[string]string{"type": "tool", "name": "turbine"},
- ExecStrategy: "${config.RETurbineExecStrategy}",
- Inputs: []string{"${config.TurbineJar}", "${out}.rsp", "$implicits"},
- RSPFiles: []string{"${out}.rsp"},
- OutputFiles: []string{"$out.tmp"},
- OutputDirectories: []string{"$outDir"},
- ToolchainInputs: []string{"${config.JavaCmd}"},
- Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
- }, []string{"javacFlags", "bootClasspath", "classpath", "srcJars", "outDir", "javaVersion"}, []string{"implicits"})
+ ExecStrategy: "${config.RETurbineExecStrategy}",
+ Inputs: []string{"${config.TurbineJar}", "${out}.rsp", "$implicits"},
+ RSPFiles: []string{"${out}.rsp"},
+ OutputFiles: []string{"$rbeOutputs"},
+ ToolchainInputs: []string{"${config.JavaCmd}"},
+ Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+ },
+ []string{"javacFlags", "turbineFlags", "outputFlags", "javaVersion", "outputs", "rbeOutputs", "srcJars"}, []string{"implicits"})
jar, jarRE = pctx.RemoteStaticRules("jar",
blueprint.RuleParams{
@@ -247,22 +244,40 @@ func init() {
}
type javaBuilderFlags struct {
- javacFlags string
- bootClasspath classpath
- classpath classpath
+ javacFlags string
+
+ // bootClasspath is the list of jars that form the boot classpath (generally the java.* and
+ // android.* classes) for tools that still use it. javac targeting 1.9 or higher uses
+ // systemModules and java9Classpath instead.
+ bootClasspath classpath
+
+ // classpath is the list of jars that form the classpath for javac and kotlinc rules. It
+ // contains header jars for all static and non-static dependencies.
+ classpath classpath
+
+ // dexClasspath is the list of jars that form the classpath for d8 and r8 rules. It contains
+ // header jars for all non-static dependencies. Static dependencies have already been
+ // combined into the program jar.
+ dexClasspath classpath
+
+ // java9Classpath is the list of jars that will be added to the classpath when targeting
+ // 1.9 or higher. It generally contains the android.* classes, while the java.* classes
+ // are provided by systemModules.
java9Classpath classpath
- processorPath classpath
- processors []string
- systemModules *systemModules
- aidlFlags string
- aidlDeps android.Paths
- javaVersion javaVersion
+
+ processorPath classpath
+ processors []string
+ systemModules *systemModules
+ aidlFlags string
+ aidlDeps android.Paths
+ javaVersion javaVersion
errorProneExtraJavacFlags string
errorProneProcessorPath classpath
kotlincFlags string
kotlincClasspath classpath
+ kotlincDeps android.Paths
proto android.ProtoFlags
}
@@ -279,23 +294,6 @@ func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.Writab
transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, flags, deps, "javac", desc)
}
-func RunErrorProne(ctx android.ModuleContext, outputFile android.WritablePath,
- srcFiles, srcJars android.Paths, flags javaBuilderFlags) {
-
- flags.processorPath = append(flags.errorProneProcessorPath, flags.processorPath...)
-
- if len(flags.errorProneExtraJavacFlags) > 0 {
- if len(flags.javacFlags) > 0 {
- flags.javacFlags += " " + flags.errorProneExtraJavacFlags
- } else {
- flags.javacFlags = flags.errorProneExtraJavacFlags
- }
- }
-
- transformJavaToClasses(ctx, outputFile, -1, srcFiles, srcJars, flags, nil,
- "errorprone", "errorprone")
-}
-
// Emits the rule to generate Xref input file (.kzip file) for the given set of source files and source jars
// to compile with given set of builder flags, etc.
func emitXrefRule(ctx android.ModuleContext, xrefFile android.WritablePath, idx int,
@@ -357,11 +355,8 @@ func emitXrefRule(ctx android.ModuleContext, xrefFile android.WritablePath, idx
})
}
-func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android.WritablePath,
- srcFiles, srcJars android.Paths, flags javaBuilderFlags) {
-
+func turbineFlags(ctx android.ModuleContext, flags javaBuilderFlags) (string, android.Paths) {
var deps android.Paths
- deps = append(deps, srcJars...)
classpath := flags.classpath
@@ -383,20 +378,31 @@ func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android.
}
deps = append(deps, classpath...)
- deps = append(deps, flags.processorPath...)
+ turbineFlags := bootClasspath + " " + classpath.FormTurbineClassPath("--classpath ")
+
+ return turbineFlags, deps
+}
+
+func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android.WritablePath,
+ srcFiles, srcJars android.Paths, flags javaBuilderFlags) {
+
+ turbineFlags, deps := turbineFlags(ctx, flags)
+
+ deps = append(deps, srcJars...)
rule := turbine
args := map[string]string{
- "javacFlags": flags.javacFlags,
- "bootClasspath": bootClasspath,
- "srcJars": strings.Join(srcJars.Strings(), " "),
- "classpath": classpath.FormTurbineClassPath("--classpath "),
- "outDir": android.PathForModuleOut(ctx, "turbine", "classes").String(),
- "javaVersion": flags.javaVersion.String(),
+ "javacFlags": flags.javacFlags,
+ "srcJars": strings.Join(srcJars.Strings(), " "),
+ "javaVersion": flags.javaVersion.String(),
+ "turbineFlags": turbineFlags,
+ "outputFlags": "--output " + outputFile.String() + ".tmp",
+ "outputs": outputFile.String(),
}
if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_TURBINE") {
rule = turbineRE
args["implicits"] = strings.Join(deps.Strings(), ",")
+ args["rbeOutputs"] = outputFile.String() + ".tmp"
}
ctx.Build(pctx, android.BuildParams{
Rule: rule,
@@ -408,6 +414,47 @@ func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android.
})
}
+// TurbineApt produces a rule to run annotation processors using turbine.
+func TurbineApt(ctx android.ModuleContext, outputSrcJar, outputResJar android.WritablePath,
+ srcFiles, srcJars android.Paths, flags javaBuilderFlags) {
+
+ turbineFlags, deps := turbineFlags(ctx, flags)
+
+ deps = append(deps, srcJars...)
+
+ deps = append(deps, flags.processorPath...)
+ turbineFlags += " " + flags.processorPath.FormTurbineClassPath("--processorpath ")
+ turbineFlags += " --processors " + strings.Join(flags.processors, " ")
+
+ outputs := android.WritablePaths{outputSrcJar, outputResJar}
+ outputFlags := "--gensrc_output " + outputSrcJar.String() + ".tmp " +
+ "--resource_output " + outputResJar.String() + ".tmp"
+
+ rule := turbine
+ args := map[string]string{
+ "javacFlags": flags.javacFlags,
+ "srcJars": strings.Join(srcJars.Strings(), " "),
+ "javaVersion": flags.javaVersion.String(),
+ "turbineFlags": turbineFlags,
+ "outputFlags": outputFlags,
+ "outputs": strings.Join(outputs.Strings(), " "),
+ }
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_TURBINE") {
+ rule = turbineRE
+ args["implicits"] = strings.Join(deps.Strings(), ",")
+ args["rbeOutputs"] = outputSrcJar.String() + ".tmp," + outputResJar.String() + ".tmp"
+ }
+ ctx.Build(pctx, android.BuildParams{
+ Rule: rule,
+ Description: "turbine apt",
+ Output: outputs[0],
+ ImplicitOutputs: outputs[1:],
+ Inputs: srcFiles,
+ Implicits: deps,
+ Args: args,
+ })
+}
+
// transformJavaToClasses takes source files and converts them to a jar containing .class files.
// srcFiles is a list of paths to sources, srcJars is a list of paths to jar files that contain
// sources. flags contains various command line flags to be passed to the compiler.
@@ -669,6 +716,6 @@ func (x *systemModules) FormTurbineSystemModulesPath(forceEmpty bool) (string, a
} else if forceEmpty {
return `--bootclasspath ""`, nil
} else {
- return "", nil
+ return "--system ${config.JavaHome}", nil
}
}
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index ecfdfb7e5..259e977d8 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -19,12 +19,13 @@ package java
import (
"fmt"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
"strings"
"android/soong/android"
)
-// Build rules and utilities to generate individual packages/modules/SdkExtensions/proto/classpaths.proto
+// Build rules and utilities to generate individual packages/modules/common/proto/classpaths.proto
// config files based on build configuration to embed into /system and /apex on a device.
//
// See `derive_classpath` service that reads the configs at runtime and defines *CLASSPATH variables
@@ -33,17 +34,23 @@ import (
type classpathType int
const (
- // Matches definition in packages/modules/SdkExtensions/proto/classpaths.proto
+ // Matches definition in packages/modules/common/proto/classpaths.proto
BOOTCLASSPATH classpathType = iota
DEX2OATBOOTCLASSPATH
SYSTEMSERVERCLASSPATH
+ STANDALONE_SYSTEMSERVER_JARS
)
func (c classpathType) String() string {
- return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH"}[c]
+ return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH", "STANDALONE_SYSTEMSERVER_JARS"}[c]
}
type classpathFragmentProperties struct {
+ // Whether to generated classpaths.proto config instance for the fragment. If the config is not
+ // generated, then relevant boot jars are added to platform classpath, i.e. platform_bootclasspath
+ // or platform_systemserverclasspath. This is useful for non-updatable APEX boot jars, to keep
+ // them as part of dexopt on device. Defaults to true.
+ Generate_classpaths_proto *bool
}
// classpathFragment interface is implemented by a module that contributes jars to a *CLASSPATH
@@ -52,10 +59,6 @@ type classpathFragment interface {
android.Module
classpathFragmentBase() *ClasspathFragmentBase
-
- // ClasspathFragmentToConfiguredJarList returns android.ConfiguredJarList representation of all
- // the jars in this classpath fragment.
- ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList
}
// ClasspathFragmentBase is meant to be embedded in any module types that implement classpathFragment;
@@ -82,15 +85,14 @@ func initClasspathFragment(c classpathFragment, classpathType classpathType) {
// Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto
type classpathJar struct {
- path string
- classpath classpathType
- // TODO(satayev): propagate min/max sdk versions for the jars
- minSdkVersion int32
- maxSdkVersion int32
+ path string
+ classpath classpathType
+ minSdkVersion string
+ maxSdkVersion string
}
-// gatherPossibleUpdatableModuleNamesAndStems returns a set of module and stem names from the
-// supplied contents that may be in the updatable boot jars.
+// gatherPossibleApexModuleNamesAndStems returns a set of module and stem names from the
+// supplied contents that may be in the apex boot jars.
//
// The module names are included because sometimes the stem is set to just change the name of
// the installed file and it expects the configuration to still use the actual module name.
@@ -98,7 +100,7 @@ type classpathJar struct {
// The stem names are included because sometimes the stem is set to change the effective name of the
// module that is used in the configuration as well,e .g. when a test library is overriding an
// actual boot jar
-func gatherPossibleUpdatableModuleNamesAndStems(ctx android.ModuleContext, contents []string, tag blueprint.DependencyTag) []string {
+func gatherPossibleApexModuleNamesAndStems(ctx android.ModuleContext, contents []string, tag blueprint.DependencyTag) []string {
set := map[string]struct{}{}
for _, name := range contents {
dep := ctx.GetDirectDepWithTag(name, tag)
@@ -118,58 +120,79 @@ func configuredJarListToClasspathJars(ctx android.ModuleContext, configuredJars
jars := make([]classpathJar, 0, len(paths)*len(classpaths))
for i := 0; i < len(paths); i++ {
for _, classpathType := range classpaths {
- jars = append(jars, classpathJar{
+ jar := classpathJar{
classpath: classpathType,
path: paths[i],
+ }
+ ctx.VisitDirectDepsIf(func(m android.Module) bool {
+ return m.Name() == configuredJars.Jar(i)
+ }, func(m android.Module) {
+ if s, ok := m.(*SdkLibrary); ok {
+ // TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current"
+ if s.minSdkVersion.Specified() {
+ if s.minSdkVersion.ApiLevel.IsCurrent() {
+ jar.minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
+ } else {
+ jar.minSdkVersion = s.minSdkVersion.ApiLevel.String()
+ }
+ }
+ if s.maxSdkVersion.Specified() {
+ if s.maxSdkVersion.ApiLevel.IsCurrent() {
+ jar.maxSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
+ } else {
+ jar.maxSdkVersion = s.maxSdkVersion.ApiLevel.String()
+ }
+ }
+ }
})
+ jars = append(jars, jar)
}
}
return jars
}
-func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext, jars []classpathJar) {
- outputFilename := strings.ToLower(c.classpathType.String()) + ".pb"
- c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
- c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
-
- generatedJson := android.PathForModuleOut(ctx, outputFilename+".json")
- writeClasspathsJson(ctx, generatedJson, jars)
-
- rule := android.NewRuleBuilder(pctx, ctx)
- rule.Command().
- BuiltTool("conv_classpaths_proto").
- Flag("encode").
- Flag("--format=json").
- FlagWithInput("--input=", generatedJson).
- FlagWithOutput("--output=", c.outputFilepath)
-
- rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
+func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext, configuredJars android.ConfiguredJarList, jars []classpathJar) {
+ generateProto := proptools.BoolDefault(c.properties.Generate_classpaths_proto, true)
+ if generateProto {
+ outputFilename := strings.ToLower(c.classpathType.String()) + ".pb"
+ c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
+ c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
+
+ generatedTextproto := android.PathForModuleOut(ctx, outputFilename+".textproto")
+ writeClasspathsTextproto(ctx, generatedTextproto, jars)
+
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ BuiltTool("conv_classpaths_proto").
+ Flag("encode").
+ Flag("--format=textproto").
+ FlagWithInput("--input=", generatedTextproto).
+ FlagWithOutput("--output=", c.outputFilepath)
+
+ rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
+ }
classpathProtoInfo := ClasspathFragmentProtoContentInfo{
+ ClasspathFragmentProtoGenerated: generateProto,
+ ClasspathFragmentProtoContents: configuredJars,
ClasspathFragmentProtoInstallDir: c.installDirPath,
ClasspathFragmentProtoOutput: c.outputFilepath,
}
ctx.SetProvider(ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo)
}
-func writeClasspathsJson(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
+func writeClasspathsTextproto(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
var content strings.Builder
- fmt.Fprintf(&content, "{\n")
- fmt.Fprintf(&content, "\"jars\": [\n")
- for idx, jar := range jars {
- fmt.Fprintf(&content, "{\n")
-
- fmt.Fprintf(&content, "\"path\": \"%s\",\n", jar.path)
- fmt.Fprintf(&content, "\"classpath\": \"%s\"\n", jar.classpath)
- if idx < len(jars)-1 {
- fmt.Fprintf(&content, "},\n")
- } else {
- fmt.Fprintf(&content, "}\n")
- }
+ for _, jar := range jars {
+ fmt.Fprintf(&content, "jars {\n")
+ fmt.Fprintf(&content, "path: \"%s\"\n", jar.path)
+ fmt.Fprintf(&content, "classpath: %s\n", jar.classpath)
+ fmt.Fprintf(&content, "min_sdk_version: \"%s\"\n", jar.minSdkVersion)
+ fmt.Fprintf(&content, "max_sdk_version: \"%s\"\n", jar.maxSdkVersion)
+ fmt.Fprintf(&content, "}\n")
}
- fmt.Fprintf(&content, "]\n")
- fmt.Fprintf(&content, "}\n")
+
android.WriteFileRule(ctx, output, content.String())
}
@@ -181,7 +204,7 @@ func (c *ClasspathFragmentBase) androidMkEntries() []android.AndroidMkEntries {
OutputFile: android.OptionalPathForPath(c.outputFilepath),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", c.installDirPath.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", c.installDirPath.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.outputFilepath.Base())
},
},
@@ -191,6 +214,12 @@ func (c *ClasspathFragmentBase) androidMkEntries() []android.AndroidMkEntries {
var ClasspathFragmentProtoContentInfoProvider = blueprint.NewProvider(ClasspathFragmentProtoContentInfo{})
type ClasspathFragmentProtoContentInfo struct {
+ // Whether the classpaths.proto config is generated for the fragment.
+ ClasspathFragmentProtoGenerated bool
+
+ // ClasspathFragmentProtoContents contains a list of jars that are part of this classpath fragment.
+ ClasspathFragmentProtoContents android.ConfiguredJarList
+
// ClasspathFragmentProtoOutput is an output path for the generated classpaths.proto config of this module.
//
// The file should be copied to a relevant place on device, see ClasspathFragmentProtoInstallDir
diff --git a/java/config/config.go b/java/config/config.go
index 30c6f91aa..95b841fa7 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -26,7 +26,8 @@ import (
)
var (
- pctx = android.NewPackageContext("android/soong/java/config")
+ pctx = android.NewPackageContext("android/soong/java/config")
+ exportedVars = android.NewExportedVariables(pctx)
LegacyCorePlatformBootclasspathLibraries = []string{"legacy.core.platform.api.stubs", "core-lambda-stubs"}
LegacyCorePlatformSystemModules = "legacy-core-platform-api-stubs-system-modules"
@@ -50,27 +51,43 @@ var (
"core-icu4j",
"core-oj",
"core-libart",
- // TODO: Could this be all updatable bootclasspath jars?
- "updatable-media",
- "framework-mediaprovider",
- "framework-sdkextensions",
- "android.net.ipsec.ike",
}
)
-const (
- JavaVmFlags = `-XX:OnError="cat hs_err_pid%p.log" -XX:CICompilerCount=6 -XX:+UseDynamicNumberOfGCThreads`
- JavacVmFlags = `-J-XX:OnError="cat hs_err_pid%p.log" -J-XX:CICompilerCount=6 -J-XX:+UseDynamicNumberOfGCThreads`
+var (
+ JavacVmFlags = strings.Join(javacVmFlagsList, " ")
+ javaVmFlagsList = []string{
+ `-XX:OnError="cat hs_err_pid%p.log"`,
+ "-XX:CICompilerCount=6",
+ "-XX:+UseDynamicNumberOfGCThreads",
+ }
+ javacVmFlagsList = []string{
+ `-J-XX:OnError="cat hs_err_pid%p.log"`,
+ "-J-XX:CICompilerCount=6",
+ "-J-XX:+UseDynamicNumberOfGCThreads",
+ "-J-XX:+TieredCompilation",
+ "-J-XX:TieredStopAtLevel=1",
+ }
)
func init() {
pctx.Import("github.com/google/blueprint/bootstrap")
- pctx.StaticVariable("JavacHeapSize", "2048M")
- pctx.StaticVariable("JavacHeapFlags", "-J-Xmx${JavacHeapSize}")
- pctx.StaticVariable("DexFlags", "-JXX:OnError='cat hs_err_pid%p.log' -JXX:CICompilerCount=6 -JXX:+UseDynamicNumberOfGCThreads")
+ exportedVars.ExportStringStaticVariable("JavacHeapSize", "2048M")
+ exportedVars.ExportStringStaticVariable("JavacHeapFlags", "-J-Xmx${JavacHeapSize}")
+
+ // ErrorProne can use significantly more memory than javac alone, give it a higher heap
+ // size (b/221480398).
+ exportedVars.ExportStringStaticVariable("ErrorProneHeapSize", "4096M")
+ exportedVars.ExportStringStaticVariable("ErrorProneHeapFlags", "-J-Xmx${ErrorProneHeapSize}")
+
+ exportedVars.ExportStringListStaticVariable("DexFlags", []string{
+ `-JXX:OnError="cat hs_err_pid%p.log"`,
+ "-JXX:CICompilerCount=6",
+ "-JXX:+UseDynamicNumberOfGCThreads",
+ })
- pctx.StaticVariable("CommonJdkFlags", strings.Join([]string{
+ exportedVars.ExportStringListStaticVariable("CommonJdkFlags", []string{
`-Xmaxerrs 9999999`,
`-encoding UTF-8`,
`-sourcepath ""`,
@@ -84,10 +101,10 @@ func init() {
// b/65004097: prevent using java.lang.invoke.StringConcatFactory when using -target 1.9
`-XDstringConcat=inline`,
- }, " "))
+ })
- pctx.StaticVariable("JavaVmFlags", JavaVmFlags)
- pctx.StaticVariable("JavacVmFlags", JavacVmFlags)
+ exportedVars.ExportStringListStaticVariable("JavaVmFlags", javaVmFlagsList)
+ exportedVars.ExportStringListStaticVariable("JavacVmFlags", javacVmFlagsList)
pctx.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS)
@@ -99,7 +116,12 @@ func init() {
if override := ctx.Config().Getenv("OVERRIDE_JLINK_VERSION_NUMBER"); override != "" {
return override
}
- return "11"
+ switch ctx.Config().Getenv("EXPERIMENTAL_USE_OPENJDK17_TOOLCHAIN") {
+ case "true":
+ return "17"
+ default:
+ return "11"
+ }
})
pctx.SourcePathVariable("JavaToolchain", "${JavaHome}/bin")
@@ -178,6 +200,10 @@ func init() {
hostJNIToolVariableWithSdkToolsPrebuilt("SignapkJniLibrary", "libconscrypt_openjdk_jni")
}
+func BazelJavaToolchainVars(config android.Config) string {
+ return android.BazelToolchainVars(config, exportedVars)
+}
+
func hostBinToolVariableWithSdkToolsPrebuilt(name, tool string) {
pctx.VariableFunc(name, func(ctx android.PackageVarContext) string {
if ctx.Config().AlwaysUsePrebuiltSdks() {
diff --git a/java/config/error_prone.go b/java/config/error_prone.go
index 48681b5c9..5f853c812 100644
--- a/java/config/error_prone.go
+++ b/java/config/error_prone.go
@@ -16,8 +16,6 @@ package config
import (
"strings"
-
- "android/soong/android"
)
var (
@@ -31,23 +29,23 @@ var (
)
// Wrapper that grabs value of val late so it can be initialized by a later module's init function
-func errorProneVar(name string, val *[]string, sep string) {
- pctx.VariableFunc(name, func(android.PackageVarContext) string {
+func errorProneVar(val *[]string, sep string) func() string {
+ return func() string {
return strings.Join(*val, sep)
- })
+ }
}
func init() {
- errorProneVar("ErrorProneClasspath", &ErrorProneClasspath, ":")
- errorProneVar("ErrorProneChecksError", &ErrorProneChecksError, " ")
- errorProneVar("ErrorProneChecksWarning", &ErrorProneChecksWarning, " ")
- errorProneVar("ErrorProneChecksDefaultDisabled", &ErrorProneChecksDefaultDisabled, " ")
- errorProneVar("ErrorProneChecksOff", &ErrorProneChecksOff, " ")
- errorProneVar("ErrorProneFlags", &ErrorProneFlags, " ")
- pctx.StaticVariable("ErrorProneChecks", strings.Join([]string{
+ exportedVars.ExportVariableFuncVariable("ErrorProneClasspath", errorProneVar(&ErrorProneClasspath, ":"))
+ exportedVars.ExportVariableFuncVariable("ErrorProneChecksError", errorProneVar(&ErrorProneChecksError, " "))
+ exportedVars.ExportVariableFuncVariable("ErrorProneChecksWarning", errorProneVar(&ErrorProneChecksWarning, " "))
+ exportedVars.ExportVariableFuncVariable("ErrorProneChecksDefaultDisabled", errorProneVar(&ErrorProneChecksDefaultDisabled, " "))
+ exportedVars.ExportVariableFuncVariable("ErrorProneChecksOff", errorProneVar(&ErrorProneChecksOff, " "))
+ exportedVars.ExportVariableFuncVariable("ErrorProneFlags", errorProneVar(&ErrorProneFlags, " "))
+ exportedVars.ExportStringListStaticVariable("ErrorProneChecks", []string{
"${ErrorProneChecksOff}",
"${ErrorProneChecksError}",
"${ErrorProneChecksWarning}",
"${ErrorProneChecksDefaultDisabled}",
- }, " "))
+ })
}
diff --git a/java/config/kotlin.go b/java/config/kotlin.go
index 6cb61f306..fc63f4dfb 100644
--- a/java/config/kotlin.go
+++ b/java/config/kotlin.go
@@ -34,6 +34,7 @@ func init() {
pctx.SourcePathVariable("KotlinKaptJar", "external/kotlinc/lib/kotlin-annotation-processing.jar")
pctx.SourcePathVariable("KotlinAnnotationJar", "external/kotlinc/lib/annotations-13.0.jar")
pctx.SourcePathVariable("KotlinStdlibJar", KotlinStdlibJar)
+ pctx.SourcePathVariable("KotlinAbiGenPluginJar", "external/kotlinc/lib/jvm-abi-gen.jar")
// These flags silence "Illegal reflective access" warnings when running kapt in OpenJDK9+
pctx.StaticVariable("KaptSuppressJDK9Warnings", strings.Join([]string{
@@ -47,4 +48,9 @@ func init() {
pctx.StaticVariable("KotlincSuppressJDK9Warnings", strings.Join([]string{
"-J--add-opens=java.base/java.util=ALL-UNNAMED", // https://youtrack.jetbrains.com/issue/KT-43704
}, " "))
+
+ pctx.StaticVariable("KotlincGlobalFlags", strings.Join([]string{
+ // b/222162908: prevent kotlinc from reading /tmp/build.txt
+ "-Didea.plugins.compatible.build=999.SNAPSHOT",
+ }, " "))
}
diff --git a/java/core-libraries/Android.bp b/java/core-libraries/Android.bp
new file mode 100644
index 000000000..cf3974601
--- /dev/null
+++ b/java/core-libraries/Android.bp
@@ -0,0 +1,225 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//
+// Definitions for building the Android core libraries, i.e. ART, I18n and
+// Conscrypt.
+//
+// These are here as the definitions are used by the build itself and include
+// parts from all three of those modules.
+//
+
+// A stubs target containing the parts of the public SDK API provided by the
+// core libraries.
+//
+// Don't use this directly, use "sdk_version: core_current".
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+dist_targets = [
+ "sdk",
+ "win_sdk",
+]
+
+java_library {
+ name: "core.current.stubs",
+ visibility: ["//visibility:public"],
+ static_libs: [
+ "art.module.public.api.stubs",
+ "conscrypt.module.public.api.stubs",
+ "i18n.module.public.api.stubs",
+ ],
+ sdk_version: "none",
+ system_modules: "none",
+
+ dist: {
+ targets: dist_targets,
+ },
+}
+
+// Distributed with the SDK for turning into system modules to compile apps
+// against.
+//
+// Also, produces dist files that are used by the
+// prebuilts/sdk/update_prebuilts.py script to update the prebuilts/sdk
+// directory.
+java_library {
+ name: "core-current-stubs-for-system-modules",
+ visibility: ["//development/sdk"],
+ static_libs: [
+ "core.current.stubs",
+ // This one is not on device but it's needed when javac compiles code
+ // containing lambdas.
+ "core-lambda-stubs-for-system-modules",
+ // This one is not on device but it's needed when javac compiles code
+ // containing @Generated annotations produced by some code generation
+ // tools.
+ // See http://b/123891440.
+ "core-generated-annotation-stubs",
+ ],
+ sdk_version: "none",
+ system_modules: "none",
+ dists: [
+ {
+ // Legacy dist location for the public file.
+ dest: "core-for-system-modules.jar",
+ targets: dist_targets,
+ },
+ {
+ dest: "system-modules/public/core-for-system-modules.jar",
+ targets: dist_targets,
+ },
+ ],
+}
+
+// Used when compiling higher-level code against core.current.stubs.
+java_system_modules {
+ name: "core-public-stubs-system-modules",
+ visibility: ["//visibility:public"],
+ libs: [
+ "core-current-stubs-for-system-modules",
+ ],
+}
+
+// A stubs target containing the parts of the public SDK & @SystemApi(MODULE_LIBRARIES) API
+// provided by the core libraries.
+//
+// Don't use this directly, use "sdk_version: module_current".
+java_library {
+ name: "core.module_lib.stubs",
+ static_libs: [
+ "art.module.public.api.stubs.module_lib",
+
+ // Replace the following with the module-lib correspondence when Conscrypt or i18N module
+ // provides @SystemApi(MODULE_LIBRARIES). Currently, assume that only ART module provides
+ // @SystemApi(MODULE_LIBRARIES).
+ "conscrypt.module.public.api.stubs",
+ "i18n.module.public.api.stubs",
+ ],
+ sdk_version: "none",
+ system_modules: "none",
+ visibility: ["//visibility:private"],
+}
+
+// Produces a dist file that is used by the
+// prebuilts/sdk/update_prebuilts.py script to update the prebuilts/sdk
+// directory.
+java_library {
+ name: "core-module-lib-stubs-for-system-modules",
+ visibility: ["//visibility:private"],
+ static_libs: [
+ "core.module_lib.stubs",
+ // This one is not on device but it's needed when javac compiles code
+ // containing lambdas.
+ "core-lambda-stubs-for-system-modules",
+ // This one is not on device but it's needed when javac compiles code
+ // containing @Generated annotations produced by some code generation
+ // tools.
+ // See http://b/123891440.
+ "core-generated-annotation-stubs",
+ ],
+ sdk_version: "none",
+ system_modules: "none",
+ dist: {
+ dest: "system-modules/module-lib/core-for-system-modules.jar",
+ targets: dist_targets,
+ },
+}
+
+// Used when compiling higher-level code with sdk_version "module_current"
+java_system_modules {
+ name: "core-module-lib-stubs-system-modules",
+ libs: [
+ "core-module-lib-stubs-for-system-modules",
+ ],
+ visibility: ["//visibility:public"],
+}
+
+// Ideally this should be a restricted allowlist but there are hundreds of modules that depend on
+// this.
+// TODO(http://b/134561230) - limit the number of dependents on this.
+core_platform_visibility = ["//visibility:public"]
+
+// Libraries containing the core platform API stubs for the core libraries.
+//
+// Although this stubs library is primarily used by the Java compiler / build to indicate
+// the core platform API surface area, compile_dex: true is used so that the Core Platform
+// API annotations are available to the dex tools that enable enforcement of runtime
+// accessibility. b/119068555
+java_library {
+ name: "legacy.core.platform.api.stubs",
+ visibility: core_platform_visibility,
+ hostdex: true,
+ compile_dex: true,
+
+ sdk_version: "none",
+ system_modules: "none",
+ static_libs: [
+ "art.module.public.api.stubs.module_lib",
+ "conscrypt.module.platform.api.stubs",
+ "legacy.i18n.module.platform.api.stubs",
+ ],
+ patch_module: "java.base",
+}
+
+java_library {
+ name: "stable.core.platform.api.stubs",
+ visibility: core_platform_visibility,
+ hostdex: true,
+ compile_dex: true,
+
+ sdk_version: "none",
+ system_modules: "none",
+ static_libs: [
+ "art.module.public.api.stubs.module_lib",
+ // conscrypt only has a stable version, so it is okay to depend on it here:
+ "conscrypt.module.platform.api.stubs",
+ "stable.i18n.module.platform.api.stubs",
+ ],
+ patch_module: "java.base",
+}
+
+// Used when compiling higher-level code against *.core.platform.api.stubs.
+java_system_modules {
+ name: "legacy-core-platform-api-stubs-system-modules",
+ visibility: core_platform_visibility,
+ libs: [
+ "legacy.core.platform.api.stubs",
+ // This one is not on device but it's needed when javac compiles code
+ // containing lambdas.
+ "core-lambda-stubs-for-system-modules",
+ // This one is not on device but it's needed when javac compiles code
+ // containing @Generated annotations produced by some code generation
+ // tools.
+ // See http://b/123891440.
+ "core-generated-annotation-stubs",
+ ],
+}
+
+java_system_modules {
+ name: "stable-core-platform-api-stubs-system-modules",
+ visibility: core_platform_visibility,
+ libs: [
+ "stable.core.platform.api.stubs",
+ // This one is not on device but it's needed when javac compiles code
+ // containing lambdas.
+ "core-lambda-stubs-for-system-modules",
+ // This one is not on device but it's needed when javac compiles code
+ // containing @Generated annotations produced by some code generation
+ // tools.
+ // See http://b/123891440.
+ "core-generated-annotation-stubs",
+ ],
+}
diff --git a/java/core-libraries/OWNERS b/java/core-libraries/OWNERS
new file mode 100644
index 000000000..bb3546abd
--- /dev/null
+++ b/java/core-libraries/OWNERS
@@ -0,0 +1,3 @@
+include platform/external/icu:/OWNERS
+include platform/external/conscrypt:/OWNERS
+include platform/libcore:/OWNERS
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 39fb04a8e..4abdcc6e9 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -118,7 +118,7 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont
TransformJarsToJar(ctx, outputFile, "combine", d.implementationAndResourceJars,
android.OptionalPath{}, false, nil, nil)
d.combinedImplementationJar = outputFile
- } else {
+ } else if len(d.implementationAndResourceJars) == 1 {
d.combinedImplementationJar = d.implementationAndResourceJars[0]
}
@@ -127,7 +127,7 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont
TransformJarsToJar(ctx, outputFile, "turbine combine", d.headerJars,
android.OptionalPath{}, false, nil, []string{"META-INF/TRANSITIVE"})
d.combinedHeaderJar = outputFile
- } else {
+ } else if len(d.headerJars) == 1 {
d.combinedHeaderJar = d.headerJars[0]
}
@@ -174,7 +174,9 @@ func (d *DeviceHostConverter) AndroidMk() android.AndroidMkData {
return android.AndroidMkData{
Class: "JAVA_LIBRARIES",
OutputFile: android.OptionalPathForPath(d.combinedImplementationJar),
- Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
+ // Make does not support Windows Java modules
+ Disabled: d.Os() == android.Windows,
+ Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
Extra: []android.AndroidMkExtraFunc{
func(w io.Writer, outputFile android.Path) {
fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
diff --git a/java/dex.go b/java/dex.go
index 7898e9dff..84665e7b5 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -32,6 +32,9 @@ type DexProperties struct {
// list of module-specific flags that will be used for dex compiles
Dxflags []string `android:"arch_variant"`
+ // A list of files containing rules that specify the classes to keep in the main dex file.
+ Main_dex_rules []string `android:"path"`
+
Optimize struct {
// If false, disable all optimization. Defaults to true for android_app and android_test
// modules, false for java_library and java_test modules.
@@ -69,6 +72,9 @@ type DexProperties struct {
// This defaults to reasonable value based on module and should not be set.
// It exists only to support ART tests.
Uncompress_dex *bool
+
+ // Exclude kotlinc generate files: *.kotlin_module, *.kotlin_builtins. Defaults to false.
+ Exclude_kotlinc_generated_files *bool
}
type dexer struct {
@@ -87,11 +93,14 @@ func (d *dexer) effectiveOptimizeEnabled() bool {
var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8",
blueprint.RuleParams{
Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
- `$d8Template${config.D8Cmd} ${config.DexFlags} --output $outDir $d8Flags $in && ` +
+ `mkdir -p $$(dirname $tmpJar) && ` +
+ `${config.Zip2ZipCmd} -i $in -o $tmpJar -x '**/*.dex' && ` +
+ `$d8Template${config.D8Cmd} ${config.DexFlags} --output $outDir $d8Flags $tmpJar && ` +
`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
- `${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`,
+ `${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in`,
CommandDeps: []string{
"${config.D8Cmd}",
+ "${config.Zip2ZipCmd}",
"${config.SoongZipCmd}",
"${config.MergeZipsCmd}",
},
@@ -110,25 +119,31 @@ var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8",
ExecStrategy: "${config.RED8ExecStrategy}",
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
},
- }, []string{"outDir", "d8Flags", "zipFlags"}, nil)
+ }, []string{"outDir", "d8Flags", "zipFlags", "tmpJar", "mergeZipsFlags"}, nil)
var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8",
blueprint.RuleParams{
Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
`rm -f "$outDict" && rm -rf "${outUsageDir}" && ` +
`mkdir -p $$(dirname ${outUsage}) && ` +
- `$r8Template${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` +
+ `mkdir -p $$(dirname $tmpJar) && ` +
+ `${config.Zip2ZipCmd} -i $in -o $tmpJar -x '**/*.dex' && ` +
+ `$r8Template${config.R8Cmd} ${config.DexFlags} -injars $tmpJar --output $outDir ` +
`--no-data-resources ` +
`-printmapping ${outDict} ` +
`-printusage ${outUsage} ` +
+ `--deps-file ${out}.d ` +
`$r8Flags && ` +
`touch "${outDict}" "${outUsage}" && ` +
`${config.SoongZipCmd} -o ${outUsageZip} -C ${outUsageDir} -f ${outUsage} && ` +
`rm -rf ${outUsageDir} && ` +
`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
- `${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`,
+ `${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in`,
+ Depfile: "${out}.d",
+ Deps: blueprint.DepsGCC,
CommandDeps: []string{
"${config.R8Cmd}",
+ "${config.Zip2ZipCmd}",
"${config.SoongZipCmd}",
"${config.MergeZipsCmd}",
},
@@ -156,15 +171,22 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8",
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
},
}, []string{"outDir", "outDict", "outUsage", "outUsageZip", "outUsageDir",
- "r8Flags", "zipFlags"}, []string{"implicits"})
+ "r8Flags", "zipFlags", "tmpJar", "mergeZipsFlags"}, []string{"implicits"})
+
+func (d *dexer) dexCommonFlags(ctx android.ModuleContext,
+ minSdkVersion android.SdkSpec) (flags []string, deps android.Paths) {
-func (d *dexer) dexCommonFlags(ctx android.ModuleContext, minSdkVersion android.SdkSpec) []string {
- flags := d.dexProperties.Dxflags
+ flags = d.dexProperties.Dxflags
// Translate all the DX flags to D8 ones until all the build files have been migrated
// to D8 flags. See: b/69377755
flags = android.RemoveListFromList(flags,
[]string{"--core-library", "--dex", "--multi-dex"})
+ for _, f := range android.PathsForModuleSrc(ctx, d.dexProperties.Main_dex_rules) {
+ flags = append(flags, "--main-dex-rules", f.String())
+ deps = append(deps, f)
+ }
+
if ctx.Config().Getenv("NO_OPTIMIZE_DX") != "" {
flags = append(flags, "--debug")
}
@@ -181,15 +203,15 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext, minSdkVersion android.
}
flags = append(flags, "--min-api "+strconv.Itoa(effectiveVersion.FinalOrFutureInt()))
- return flags
+ return flags, deps
}
func d8Flags(flags javaBuilderFlags) (d8Flags []string, d8Deps android.Paths) {
d8Flags = append(d8Flags, flags.bootClasspath.FormRepeatedClassPath("--lib ")...)
- d8Flags = append(d8Flags, flags.classpath.FormRepeatedClassPath("--lib ")...)
+ d8Flags = append(d8Flags, flags.dexClasspath.FormRepeatedClassPath("--lib ")...)
d8Deps = append(d8Deps, flags.bootClasspath...)
- d8Deps = append(d8Deps, flags.classpath...)
+ d8Deps = append(d8Deps, flags.dexClasspath...)
return d8Flags, d8Deps
}
@@ -212,11 +234,11 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl
r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars"))
r8Flags = append(r8Flags, flags.bootClasspath.FormJavaClassPath("-libraryjars"))
- r8Flags = append(r8Flags, flags.classpath.FormJavaClassPath("-libraryjars"))
+ r8Flags = append(r8Flags, flags.dexClasspath.FormJavaClassPath("-libraryjars"))
r8Deps = append(r8Deps, proguardRaiseDeps...)
r8Deps = append(r8Deps, flags.bootClasspath...)
- r8Deps = append(r8Deps, flags.classpath...)
+ r8Deps = append(r8Deps, flags.dexClasspath...)
flagFiles := android.Paths{
android.PathForSource(ctx, "build/make/core/proguard.flags"),
@@ -238,6 +260,15 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl
if BoolDefault(opt.Proguard_compatibility, true) {
r8Flags = append(r8Flags, "--force-proguard-compatibility")
+ } else {
+ // TODO(b/213833843): Allow configuration of the prefix via a build variable.
+ var sourceFilePrefix = "go/retraceme "
+ var sourceFileTemplate = "\"" + sourceFilePrefix + "%MAP_ID\""
+ // TODO(b/200967150): Also tag the source file in compat builds.
+ if Bool(opt.Optimize) || Bool(opt.Obfuscate) {
+ r8Flags = append(r8Flags, "--map-id-template", "%MAP_HASH")
+ r8Flags = append(r8Flags, "--source-file-template", sourceFileTemplate)
+ }
}
// TODO(ccross): Don't shrink app instrumentation tests by default.
@@ -273,13 +304,20 @@ func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, mi
// Compile classes.jar into classes.dex and then javalib.jar
javalibJar := android.PathForModuleOut(ctx, "dex", jarName).OutputPath
outDir := android.PathForModuleOut(ctx, "dex")
+ tmpJar := android.PathForModuleOut(ctx, "withres-withoutdex", jarName)
zipFlags := "--ignore_missing_files"
if proptools.Bool(d.dexProperties.Uncompress_dex) {
zipFlags += " -L 0"
}
- commonFlags := d.dexCommonFlags(ctx, minSdkVersion)
+ commonFlags, commonDeps := d.dexCommonFlags(ctx, minSdkVersion)
+
+ // Exclude kotlinc generated files when "exclude_kotlinc_generated_files" is set to true.
+ mergeZipsFlags := ""
+ if proptools.BoolDefault(d.dexProperties.Exclude_kotlinc_generated_files, false) {
+ mergeZipsFlags = "-stripFile META-INF/*.kotlin_module -stripFile **/*.kotlin_builtins"
+ }
useR8 := d.effectiveOptimizeEnabled()
if useR8 {
@@ -291,15 +329,18 @@ func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, mi
proguardUsageZip := android.PathForModuleOut(ctx, "proguard_usage.zip")
d.proguardUsageZip = android.OptionalPathForPath(proguardUsageZip)
r8Flags, r8Deps := d.r8Flags(ctx, flags)
+ r8Deps = append(r8Deps, commonDeps...)
rule := r8
args := map[string]string{
- "r8Flags": strings.Join(append(commonFlags, r8Flags...), " "),
- "zipFlags": zipFlags,
- "outDict": proguardDictionary.String(),
- "outUsageDir": proguardUsageDir.String(),
- "outUsage": proguardUsage.String(),
- "outUsageZip": proguardUsageZip.String(),
- "outDir": outDir.String(),
+ "r8Flags": strings.Join(append(commonFlags, r8Flags...), " "),
+ "zipFlags": zipFlags,
+ "outDict": proguardDictionary.String(),
+ "outUsageDir": proguardUsageDir.String(),
+ "outUsage": proguardUsage.String(),
+ "outUsageZip": proguardUsageZip.String(),
+ "outDir": outDir.String(),
+ "tmpJar": tmpJar.String(),
+ "mergeZipsFlags": mergeZipsFlags,
}
if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8") {
rule = r8RE
@@ -316,6 +357,7 @@ func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, mi
})
} else {
d8Flags, d8Deps := d8Flags(flags)
+ d8Deps = append(d8Deps, commonDeps...)
rule := d8
if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_D8") {
rule = d8RE
@@ -327,9 +369,11 @@ func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, mi
Input: classesJar,
Implicits: d8Deps,
Args: map[string]string{
- "d8Flags": strings.Join(append(commonFlags, d8Flags...), " "),
- "zipFlags": zipFlags,
- "outDir": outDir.String(),
+ "d8Flags": strings.Join(append(commonFlags, d8Flags...), " "),
+ "zipFlags": zipFlags,
+ "outDir": outDir.String(),
+ "tmpJar": tmpJar.String(),
+ "mergeZipsFlags": mergeZipsFlags,
},
})
}
diff --git a/java/dex_test.go b/java/dex_test.go
new file mode 100644
index 000000000..fbdccb65d
--- /dev/null
+++ b/java/dex_test.go
@@ -0,0 +1,103 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "testing"
+
+ "android/soong/android"
+)
+
+func TestR8(t *testing.T) {
+ result := PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd.RunTestWithBp(t, `
+ android_app {
+ name: "app",
+ srcs: ["foo.java"],
+ libs: ["lib"],
+ static_libs: ["static_lib"],
+ platform_apis: true,
+ }
+
+ java_library {
+ name: "lib",
+ srcs: ["foo.java"],
+ }
+
+ java_library {
+ name: "static_lib",
+ srcs: ["foo.java"],
+ }
+ `)
+
+ app := result.ModuleForTests("app", "android_common")
+ lib := result.ModuleForTests("lib", "android_common")
+ staticLib := result.ModuleForTests("static_lib", "android_common")
+
+ appJavac := app.Rule("javac")
+ appR8 := app.Rule("r8")
+ libHeader := lib.Output("turbine-combined/lib.jar").Output
+ staticLibHeader := staticLib.Output("turbine-combined/static_lib.jar").Output
+
+ android.AssertStringDoesContain(t, "expected lib header jar in app javac classpath",
+ appJavac.Args["classpath"], libHeader.String())
+ android.AssertStringDoesContain(t, "expected static_lib header jar in app javac classpath",
+ appJavac.Args["classpath"], staticLibHeader.String())
+
+ android.AssertStringDoesContain(t, "expected lib header jar in app r8 classpath",
+ appR8.Args["r8Flags"], libHeader.String())
+ android.AssertStringDoesNotContain(t, "expected no static_lib header jar in app javac classpath",
+ appR8.Args["r8Flags"], staticLibHeader.String())
+}
+
+func TestD8(t *testing.T) {
+ result := PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd.RunTestWithBp(t, `
+ java_library {
+ name: "foo",
+ srcs: ["foo.java"],
+ libs: ["lib"],
+ static_libs: ["static_lib"],
+ installable: true,
+ }
+
+ java_library {
+ name: "lib",
+ srcs: ["foo.java"],
+ }
+
+ java_library {
+ name: "static_lib",
+ srcs: ["foo.java"],
+ }
+ `)
+
+ foo := result.ModuleForTests("foo", "android_common")
+ lib := result.ModuleForTests("lib", "android_common")
+ staticLib := result.ModuleForTests("static_lib", "android_common")
+
+ fooJavac := foo.Rule("javac")
+ fooD8 := foo.Rule("d8")
+ libHeader := lib.Output("turbine-combined/lib.jar").Output
+ staticLibHeader := staticLib.Output("turbine-combined/static_lib.jar").Output
+
+ android.AssertStringDoesContain(t, "expected lib header jar in foo javac classpath",
+ fooJavac.Args["classpath"], libHeader.String())
+ android.AssertStringDoesContain(t, "expected static_lib header jar in foo javac classpath",
+ fooJavac.Args["classpath"], staticLibHeader.String())
+
+ android.AssertStringDoesContain(t, "expected lib header jar in foo d8 classpath",
+ fooD8.Args["d8Flags"], libHeader.String())
+ android.AssertStringDoesNotContain(t, "expected no static_lib header jar in foo javac classpath",
+ fooD8.Args["d8Flags"], staticLibHeader.String())
+}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 2e46d74fa..7c5f055e6 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -15,13 +15,65 @@
package java
import (
+ "path/filepath"
+ "strings"
+
"android/soong/android"
"android/soong/dexpreopt"
)
-type dexpreopterInterface interface {
+type DexpreopterInterface interface {
IsInstallable() bool // Structs that embed dexpreopter must implement this.
dexpreoptDisabled(ctx android.BaseModuleContext) bool
+ DexpreoptBuiltInstalledForApex() []dexpreopterInstall
+ AndroidMkEntriesForApex() []android.AndroidMkEntries
+}
+
+type dexpreopterInstall struct {
+ // A unique name to distinguish an output from others for the same java library module. Usually in
+ // the form of `<arch>-<encoded-path>.odex/vdex/art`.
+ name string
+
+ // The name of the input java module.
+ moduleName string
+
+ // The path to the dexpreopt output on host.
+ outputPathOnHost android.Path
+
+ // The directory on the device for the output to install to.
+ installDirOnDevice android.InstallPath
+
+ // The basename (the last segment of the path) for the output to install as.
+ installFileOnDevice string
+}
+
+// The full module name of the output in the makefile.
+func (install *dexpreopterInstall) FullModuleName() string {
+ return install.moduleName + install.SubModuleName()
+}
+
+// The sub-module name of the output in the makefile (the name excluding the java module name).
+func (install *dexpreopterInstall) SubModuleName() string {
+ return "-dexpreopt-" + install.name
+}
+
+// Returns Make entries for installing the file.
+//
+// This function uses a value receiver rather than a pointer receiver to ensure that the object is
+// safe to use in `android.AndroidMkExtraEntriesFunc`.
+func (install dexpreopterInstall) ToMakeEntries() android.AndroidMkEntries {
+ return android.AndroidMkEntries{
+ Class: "ETC",
+ SubName: install.SubModuleName(),
+ OutputFile: android.OptionalPathForPath(install.outputPathOnHost),
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.String())
+ entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice)
+ entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false")
+ },
+ },
+ }
}
type dexpreopter struct {
@@ -33,13 +85,16 @@ type dexpreopter struct {
isApp bool
isTest bool
isPresignedPrebuilt bool
+ preventInstall bool
manifestFile android.Path
statusFile android.WritablePath
enforceUsesLibs bool
classLoaderContexts dexpreopt.ClassLoaderContextMap
- builtInstalled string
+ // See the `dexpreopt` function for details.
+ builtInstalled string
+ builtInstalledForApex []dexpreopterInstall
// The config is used for two purposes:
// - Passing dexpreopt information about libraries from Soong to Make. This is needed when
@@ -74,14 +129,24 @@ func init() {
dexpreopt.DexpreoptRunningInSoong = true
}
-func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
- global := dexpreopt.GetGlobalConfig(ctx)
+func isApexVariant(ctx android.BaseModuleContext) bool {
+ apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ return !apexInfo.IsForPlatform()
+}
- if global.DisablePreopt {
- return true
- }
+func forPrebuiltApex(ctx android.BaseModuleContext) bool {
+ apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ return apexInfo.ForPrebuiltApex
+}
+
+func moduleName(ctx android.BaseModuleContext) string {
+ // Remove the "prebuilt_" prefix if the module is from a prebuilt because the prefix is not
+ // expected by dexpreopter.
+ return android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName())
+}
- if inList(ctx.ModuleName(), global.DisablePreoptModules) {
+func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
+ if !ctx.Device() {
return true
}
@@ -93,36 +158,80 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
return true
}
- if !ctx.Module().(dexpreopterInterface).IsInstallable() {
+ // If the module is from a prebuilt APEX, it shouldn't be installable, but it can still be
+ // dexpreopted.
+ if !ctx.Module().(DexpreopterInterface).IsInstallable() && !forPrebuiltApex(ctx) {
return true
}
- if ctx.Host() {
+ if !android.IsModulePreferred(ctx.Module()) {
return true
}
- // Don't preopt APEX variant module
- if apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo); !apexInfo.IsForPlatform() {
+ global := dexpreopt.GetGlobalConfig(ctx)
+
+ if global.DisablePreopt {
return true
}
+ if inList(moduleName(ctx), global.DisablePreoptModules) {
+ return true
+ }
+
+ isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx))
+ if isApexVariant(ctx) {
+ // Don't preopt APEX variant module unless the module is an APEX system server jar and we are
+ // building the entire system image.
+ if !isApexSystemServerJar || ctx.Config().UnbundledBuild() {
+ return true
+ }
+ } else {
+ // Don't preopt the platform variant of an APEX system server jar to avoid conflicts.
+ if isApexSystemServerJar {
+ return true
+ }
+ }
+
// TODO: contains no java code
return false
}
func dexpreoptToolDepsMutator(ctx android.BottomUpMutatorContext) {
- if d, ok := ctx.Module().(dexpreopterInterface); !ok || d.dexpreoptDisabled(ctx) {
+ if d, ok := ctx.Module().(DexpreopterInterface); !ok || d.dexpreoptDisabled(ctx) {
return
}
dexpreopt.RegisterToolDeps(ctx)
}
-func odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool {
- return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx))
+func (d *dexpreopter) odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool {
+ return dexpreopt.OdexOnSystemOtherByName(moduleName(ctx), android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx))
+}
+
+// Returns the install path of the dex jar of a module.
+//
+// Do not rely on `ApexInfo.ApexVariationName` because it can be something like "apex1000", rather
+// than the `name` in the path `/apex/<name>` as suggested in its comment.
+//
+// This function is on a best-effort basis. It cannot handle the case where an APEX jar is not a
+// system server jar, which is fine because we currently only preopt system server jars for APEXes.
+func (d *dexpreopter) getInstallPath(
+ ctx android.ModuleContext, defaultInstallPath android.InstallPath) android.InstallPath {
+ global := dexpreopt.GetGlobalConfig(ctx)
+ if global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx)) {
+ dexLocation := dexpreopt.GetSystemServerDexLocation(ctx, global, moduleName(ctx))
+ return android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexLocation, "/"))
+ }
+ if !d.dexpreoptDisabled(ctx) && isApexVariant(ctx) &&
+ filepath.Base(defaultInstallPath.PartitionDir()) != "apex" {
+ ctx.ModuleErrorf("unable to get the install path of the dex jar for dexpreopt")
+ }
+ return defaultInstallPath
}
func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.WritablePath) {
+ global := dexpreopt.GetGlobalConfig(ctx)
+
// TODO(b/148690468): The check on d.installPath is to bail out in cases where
// the dexpreopter struct hasn't been fully initialized before we're called,
// e.g. in aar.go. This keeps the behaviour that dexpreopting is effectively
@@ -133,7 +242,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
- providesUsesLib := ctx.ModuleName()
+ providesUsesLib := moduleName(ctx)
if ulib, ok := ctx.Module().(ProvidesUsesLib); ok {
name := ulib.ProvidesUsesLib()
if name != nil {
@@ -141,24 +250,20 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
}
}
- // If it is neither app nor test, make config files regardless of its dexpreopt setting.
+ // If it is test, make config files regardless of its dexpreopt setting.
// The config files are required for apps defined in make which depend on the lib.
- // TODO(b/158843648): The config for apps should be generated as well regardless of setting.
- if (d.isApp || d.isTest) && d.dexpreoptDisabled(ctx) {
+ if d.isTest && d.dexpreoptDisabled(ctx) {
return
}
- global := dexpreopt.GetGlobalConfig(ctx)
-
- isSystemServerJar := global.SystemServerJars.ContainsJar(ctx.ModuleName())
+ isSystemServerJar := global.AllSystemServerJars(ctx).ContainsJar(moduleName(ctx))
bootImage := defaultBootImageConfig(ctx)
if global.UseArtImage {
bootImage = artBootImageConfig(ctx)
}
- // System server jars are an exception: they are dexpreopted without updatable bootclasspath.
- dexFiles, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp && !isSystemServerJar)
+ dexFiles, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp)
targets := ctx.MultiTargets()
if len(targets) == 0 {
@@ -200,15 +305,15 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
profileIsTextListing = true
} else if global.ProfileDir != "" {
profileClassListing = android.ExistentPathForSource(ctx,
- global.ProfileDir, ctx.ModuleName()+".prof")
+ global.ProfileDir, moduleName(ctx)+".prof")
}
}
// Full dexpreopt config, used to create dexpreopt build rules.
dexpreoptConfig := &dexpreopt.ModuleConfig{
- Name: ctx.ModuleName(),
+ Name: moduleName(ctx),
DexLocation: dexLocation,
- BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath,
+ BuildPath: android.PathForModuleOut(ctx, "dexpreopt", moduleName(ctx)+".jar").OutputPath,
DexPath: dexJarFile,
ManifestPath: android.OptionalPathForPath(d.manifestFile),
UncompressedDex: d.uncompressedDex,
@@ -257,5 +362,47 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
dexpreoptRule.Build("dexpreopt", "dexpreopt")
- d.builtInstalled = dexpreoptRule.Installs().String()
+ isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx))
+
+ for _, install := range dexpreoptRule.Installs() {
+ // Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
+ installDir := strings.TrimPrefix(filepath.Dir(install.To), "/")
+ installBase := filepath.Base(install.To)
+ arch := filepath.Base(installDir)
+ installPath := android.PathForModuleInPartitionInstall(ctx, "", installDir)
+
+ if isApexSystemServerJar {
+ // APEX variants of java libraries are hidden from Make, so their dexpreopt
+ // outputs need special handling. Currently, for APEX variants of java
+ // libraries, only those in the system server classpath are handled here.
+ // Preopting of boot classpath jars in the ART APEX are handled in
+ // java/dexpreopt_bootjars.go, and other APEX jars are not preopted.
+ // The installs will be handled by Make as sub-modules of the java library.
+ d.builtInstalledForApex = append(d.builtInstalledForApex, dexpreopterInstall{
+ name: arch + "-" + installBase,
+ moduleName: moduleName(ctx),
+ outputPathOnHost: install.From,
+ installDirOnDevice: installPath,
+ installFileOnDevice: installBase,
+ })
+ } else if !d.preventInstall {
+ ctx.InstallFile(installPath, installBase, install.From)
+ }
+ }
+
+ if !isApexSystemServerJar {
+ d.builtInstalled = dexpreoptRule.Installs().String()
+ }
+}
+
+func (d *dexpreopter) DexpreoptBuiltInstalledForApex() []dexpreopterInstall {
+ return d.builtInstalledForApex
+}
+
+func (d *dexpreopter) AndroidMkEntriesForApex() []android.AndroidMkEntries {
+ var entries []android.AndroidMkEntries
+ for _, install := range d.builtInstalledForApex {
+ entries = append(entries, install.ToMakeEntries())
+ }
+ return entries
}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 19c65cac7..3d91aec91 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -16,7 +16,6 @@ package java
import (
"path/filepath"
- "sort"
"strings"
"android/soong/android"
@@ -154,12 +153,23 @@ import (
// PRODUCT_BOOT_JARS_EXTRA variables. The AOSP makefiles specify some common Framework libraries,
// but more product-specific libraries can be added in the product makefiles.
//
-// Each component of the PRODUCT_BOOT_JARS and PRODUCT_BOOT_JARS_EXTRA variables is either a simple
-// name (if the library is a part of the Platform), or a colon-separated pair <apex, name> (if the
-// library is a part of a non-updatable APEX).
+// Each component of the PRODUCT_BOOT_JARS and PRODUCT_BOOT_JARS_EXTRA variables is a
+// colon-separated pair <apex>:<library>, where <apex> is the variant name of a non-updatable APEX,
+// "platform" if the library is a part of the platform in the system partition, or "system_ext" if
+// it's in the system_ext partition.
//
-// A related variable PRODUCT_UPDATABLE_BOOT_JARS contains bootclasspath libraries that are in
-// updatable APEXes. They are not included in the boot image.
+// In these variables APEXes are identified by their "variant names", i.e. the names they get
+// mounted as in /apex on device. In Soong modules that is the name set in the "apex_name"
+// properties, which default to the "name" values. For example, many APEXes have both
+// com.android.xxx and com.google.android.xxx modules in Soong, but take the same place
+// /apex/com.android.xxx at runtime. In these cases the variant name is always com.android.xxx,
+// regardless which APEX goes into the product. See also android.ApexInfo.ApexVariationName and
+// apex.apexBundleProperties.Apex_name.
+//
+// A related variable PRODUCT_APEX_BOOT_JARS contains bootclasspath libraries that are in APEXes.
+// They are not included in the boot image. The only exception here are ART jars and core-icu4j.jar
+// that have been historically part of the boot image and are now in apexes; they are in boot images
+// and core-icu4j.jar is generally treated as being part of PRODUCT_BOOT_JARS.
//
// One exception to the above rules are "coverage" builds (a special build flavor which requires
// setting environment variable EMMA_INSTRUMENT_FRAMEWORK=true). In coverage builds the Java code in
@@ -246,6 +256,10 @@ type bootImageConfig struct {
// Subdirectory where the image files on device are installed.
installDirOnDevice string
+ // Install path of the boot image profile if it needs to be installed in the APEX, or empty if not
+ // needed.
+ profileInstallPathInApex string
+
// A list of (location, jar) pairs for the Java modules in this image.
modules android.ConfiguredJarList
@@ -262,8 +276,17 @@ type bootImageConfig struct {
// Rules which should be used in make to install the outputs.
profileInstalls android.RuleBuilderInstalls
+ // Path to the license metadata file for the module that built the profile.
+ profileLicenseMetadataFile android.OptionalPath
+
+ // Path to the image profile file on host (or empty, if profile is not generated).
+ profilePathOnHost android.Path
+
// Target-dependent fields.
variants []*bootImageVariant
+
+ // Path of the preloaded classes file.
+ preloadedClassesFile string
}
// Target-dependent description of a boot image.
@@ -296,10 +319,16 @@ type bootImageVariant struct {
// This is only set for a variant of an image that extends another image.
primaryImagesDeps android.Paths
- // Rules which should be used in make to install the outputs.
+ // Rules which should be used in make to install the outputs on host.
installs android.RuleBuilderInstalls
vdexInstalls android.RuleBuilderInstalls
unstrippedInstalls android.RuleBuilderInstalls
+
+ // Rules which should be used in make to install the outputs on device.
+ deviceInstalls android.RuleBuilderInstalls
+
+ // Path to the license metadata file for the module that built the image.
+ licenseMetadataFile android.OptionalPath
}
// Get target-specific boot image variant for the given boot image config and target.
@@ -371,6 +400,11 @@ func (image *bootImageConfig) apexVariants() []*bootImageVariant {
return variants
}
+// Returns true if the boot image should be installed in the APEX.
+func (image *bootImageConfig) shouldInstallInApex() bool {
+ return strings.HasPrefix(image.installDirOnDevice, "apex/")
+}
+
// Return boot image locations (as a list of symbolic paths).
//
// The image "location" is a symbolic path that, with multiarchitecture support, doesn't really
@@ -489,7 +523,21 @@ func copyBootJarsToPredefinedLocations(ctx android.ModuleContext, srcBootDexJars
dst := dstBootJarsByModule[name]
if src == nil {
- ctx.ModuleErrorf("module %s does not provide a dex boot jar", name)
+ // A dex boot jar should be provided by the source java module. It needs to be installable or
+ // have compile_dex=true - cf. assignments to java.Module.dexJarFile.
+ //
+ // However, the source java module may be either replaced or overridden (using prefer:true) by
+ // a prebuilt java module with the same name. In that case the dex boot jar needs to be
+ // provided by the corresponding prebuilt APEX module. That APEX is the one that refers
+ // through a exported_(boot|systemserver)classpath_fragments property to a
+ // prebuilt_(boot|systemserver)classpath_fragment module, which in turn lists the prebuilt
+ // java module in the contents property. If that chain is broken then this dependency will
+ // fail.
+ if !ctx.Config().AllowMissingDependencies() {
+ ctx.ModuleErrorf("module %s does not provide a dex boot jar (see comment next to this message in Soong for details)", name)
+ } else {
+ ctx.AddMissingDependencies([]string{name})
+ }
} else if dst == nil {
ctx.ModuleErrorf("module %s is not part of the boot configuration", name)
} else {
@@ -512,14 +560,14 @@ func buildBootImageVariantsForAndroidOs(ctx android.ModuleContext, image *bootIm
}
// buildBootImageVariantsForBuildOs generates rules to build the boot image variants for the
-// android.BuildOs OsType, i.e. the type of OS on which the build is being running.
+// config.BuildOS OsType, i.e. the type of OS on which the build is being running.
//
// The files need to be generated into their predefined location because they are used from there
// both within Soong and outside, e.g. for ART based host side testing and also for use by some
// cloud based tools. However, they are not needed by callers of this function and so the paths do
// not need to be returned from this func, unlike the buildBootImageVariantsForAndroidOs func.
func buildBootImageVariantsForBuildOs(ctx android.ModuleContext, image *bootImageConfig, profile android.WritablePath) {
- buildBootImageForOsType(ctx, image, profile, android.BuildOs)
+ buildBootImageForOsType(ctx, image, profile, ctx.Config().BuildOS)
}
// buildBootImageForOsType takes a bootImageConfig, a profile file and an android.OsType
@@ -611,7 +659,6 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p
Flag("--runtime-arg").FlagWithArg("-Xmx", global.Dex2oatImageXmx)
if profile != nil {
- cmd.FlagWithArg("--compiler-filter=", "speed-profile")
cmd.FlagWithInput("--profile-file=", profile)
}
@@ -642,6 +689,13 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p
cmd.FlagWithArg("--base=", ctx.Config().LibartImgDeviceBaseAddress())
}
+ // We always expect a preloaded classes file to be available. However, if we cannot find it, it's
+ // OK to not pass the flag to dex2oat.
+ preloadedClassesPath := android.ExistentPathForSource(ctx, image.preloadedClassesFile)
+ if preloadedClassesPath.Valid() {
+ cmd.FlagWithInput("--preloaded-classes=", preloadedClassesPath.Path())
+ }
+
cmd.
FlagForEachInput("--dex-file=", image.dexPaths.Paths()).
FlagForEachArg("--dex-location=", image.dexLocations).
@@ -680,6 +734,7 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p
var vdexInstalls android.RuleBuilderInstalls
var unstrippedInstalls android.RuleBuilderInstalls
+ var deviceInstalls android.RuleBuilderInstalls
for _, artOrOat := range image.moduleFiles(ctx, outputDir, ".art", ".oat") {
cmd.ImplicitOutput(artOrOat)
@@ -705,12 +760,22 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p
android.RuleBuilderInstall{unstrippedOat, filepath.Join(installDir, unstrippedOat.Base())})
}
+ if image.installDirOnHost != image.installDirOnDevice && !image.shouldInstallInApex() && !ctx.Config().UnbundledBuild() {
+ installDirOnDevice := filepath.Join("/", image.installDirOnDevice, arch.String())
+ for _, file := range image.moduleFiles(ctx, outputDir, ".art", ".oat", ".vdex") {
+ deviceInstalls = append(deviceInstalls,
+ android.RuleBuilderInstall{file, filepath.Join(installDirOnDevice, file.Base())})
+ }
+ }
+
rule.Build(image.name+"JarsDexpreopt_"+image.target.String(), "dexpreopt "+image.name+" jars "+arch.String())
// save output and installed files for makevars
image.installs = rule.Installs()
image.vdexInstalls = vdexInstalls
image.unstrippedInstalls = unstrippedInstalls
+ image.deviceInstalls = deviceInstalls
+ image.licenseMetadataFile = android.OptionalPathForPath(ctx.LicenseMetadataFile())
}
const failureMessage = `ERROR: Dex2oat failed to compile a boot image.
@@ -756,11 +821,15 @@ func bootImageProfileRule(ctx android.ModuleContext, image *bootImageConfig) and
FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps).
FlagWithOutput("--reference-profile-file=", profile)
- rule.Install(profile, "/system/etc/boot-image.prof")
+ if image == defaultBootImageConfig(ctx) {
+ rule.Install(profile, "/system/etc/boot-image.prof")
+ image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
+ image.profileLicenseMetadataFile = android.OptionalPathForPath(ctx.LicenseMetadataFile())
+ }
rule.Build("bootJarsProfile", "profile boot jars")
- image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
+ image.profilePathOnHost = profile
return profile
}
@@ -793,44 +862,11 @@ func bootFrameworkProfileRule(ctx android.ModuleContext, image *bootImageConfig)
rule.Install(profile, "/system/etc/boot-image.bprof")
rule.Build("bootFrameworkProfile", "profile boot framework jars")
image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
+ image.profileLicenseMetadataFile = android.OptionalPathForPath(ctx.LicenseMetadataFile())
return profile
}
-// generateUpdatableBcpPackagesRule generates the rule to create the updatable-bcp-packages.txt file
-// and returns a path to the generated file.
-func generateUpdatableBcpPackagesRule(ctx android.ModuleContext, image *bootImageConfig, updatableModules []android.Module) android.WritablePath {
- // Collect `permitted_packages` for updatable boot jars.
- var updatablePackages []string
- for _, module := range updatableModules {
- if j, ok := module.(PermittedPackagesForUpdatableBootJars); ok {
- pp := j.PermittedPackagesForUpdatableBootJars()
- if len(pp) > 0 {
- updatablePackages = append(updatablePackages, pp...)
- } else {
- ctx.OtherModuleErrorf(module, "Missing permitted_packages")
- }
- }
- }
-
- // Sort updatable packages to ensure deterministic ordering.
- sort.Strings(updatablePackages)
-
- updatableBcpPackagesName := "updatable-bcp-packages.txt"
- updatableBcpPackages := image.dir.Join(ctx, updatableBcpPackagesName)
-
- // WriteFileRule automatically adds the last end-of-line.
- android.WriteFileRule(ctx, updatableBcpPackages, strings.Join(updatablePackages, "\n"))
-
- rule := android.NewRuleBuilder(pctx, ctx)
- rule.Install(updatableBcpPackages, "/system/etc/"+updatableBcpPackagesName)
- // TODO: Rename `profileInstalls` to `extraInstalls`?
- // Maybe even move the field out of the bootImageConfig into some higher level type?
- image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
-
- return updatableBcpPackages
-}
-
func dumpOatRules(ctx android.ModuleContext, image *bootImageConfig) {
var allPhonies android.Paths
for _, image := range image.variants {
@@ -892,6 +928,9 @@ func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) {
image := d.defaultBootImage
if image != nil {
ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String())
+ if image.profileLicenseMetadataFile.Valid() {
+ ctx.Strict("DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA", image.profileLicenseMetadataFile.String())
+ }
global := dexpreopt.GetGlobalConfig(ctx)
dexPaths, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp)
@@ -917,6 +956,9 @@ func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) {
ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(variant.imagesDeps.Strings(), " "))
ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, variant.installs.String())
ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, variant.unstrippedInstalls.String())
+ if variant.licenseMetadataFile.Valid() {
+ ctx.Strict("DEXPREOPT_IMAGE_LICENSE_METADATA_"+sfx, variant.licenseMetadataFile.String())
+ }
}
imageLocationsOnHost, imageLocationsOnDevice := current.getAnyAndroidVariant().imageLocations()
ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_ON_HOST"+current.name, strings.Join(imageLocationsOnHost, ":"))
diff --git a/java/dexpreopt_check.go b/java/dexpreopt_check.go
new file mode 100644
index 000000000..83c088cd4
--- /dev/null
+++ b/java/dexpreopt_check.go
@@ -0,0 +1,96 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "strings"
+
+ "android/soong/android"
+ "android/soong/dexpreopt"
+
+ "github.com/google/blueprint/pathtools"
+)
+
+func init() {
+ RegisterDexpreoptCheckBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterDexpreoptCheckBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterSingletonModuleType("dexpreopt_systemserver_check", dexpreoptSystemserverCheckFactory)
+}
+
+// A build-time check to verify if all compilation artifacts of system server jars are installed
+// into the system image. When the check fails, it means that dexpreopting is not working for some
+// system server jars and needs to be fixed.
+// This singleton module generates a list of the paths to the artifacts based on
+// PRODUCT_SYSTEM_SERVER_JARS and PRODUCT_APEX_SYSTEM_SERVER_JARS, and passes it to Make via a
+// variable. Make will then do the actual check.
+// Currently, it only checks artifacts of modules defined in Soong. Artifacts of modules defined in
+// Makefile are generated by a script generated by dexpreopt_gen, and their existence is unknown to
+// Make and Ninja.
+type dexpreoptSystemserverCheck struct {
+ android.SingletonModuleBase
+
+ // Mapping from the module name to the install paths to the compilation artifacts.
+ artifactsByModuleName map[string][]string
+
+ // The install paths to the compilation artifacts.
+ artifacts []string
+}
+
+func dexpreoptSystemserverCheckFactory() android.SingletonModule {
+ m := &dexpreoptSystemserverCheck{}
+ m.artifactsByModuleName = make(map[string][]string)
+ android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
+ return m
+}
+
+func getInstallPath(ctx android.ModuleContext, location string) android.InstallPath {
+ return android.PathForModuleInPartitionInstall(
+ ctx, "", strings.TrimPrefix(location, "/"))
+}
+
+func (m *dexpreoptSystemserverCheck) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ global := dexpreopt.GetGlobalConfig(ctx)
+ targets := ctx.Config().Targets[android.Android]
+
+ // The check should be skipped on unbundled builds because system server jars are not preopted on
+ // unbundled builds since the artifacts are installed into the system image, not the APEXes.
+ if global.DisablePreopt || len(targets) == 0 || ctx.Config().UnbundledBuild() {
+ return
+ }
+
+ systemServerJars := global.AllSystemServerJars(ctx)
+ for _, jar := range systemServerJars.CopyOfJars() {
+ dexLocation := dexpreopt.GetSystemServerDexLocation(ctx, global, jar)
+ odexLocation := dexpreopt.ToOdexPath(dexLocation, targets[0].Arch.ArchType)
+ odexPath := getInstallPath(ctx, odexLocation)
+ vdexPath := getInstallPath(ctx, pathtools.ReplaceExtension(odexLocation, "vdex"))
+ m.artifactsByModuleName[jar] = []string{odexPath.String(), vdexPath.String()}
+ }
+}
+
+func (m *dexpreoptSystemserverCheck) GenerateSingletonBuildActions(ctx android.SingletonContext) {
+ // Only keep modules defined in Soong.
+ ctx.VisitAllModules(func(module android.Module) {
+ if artifacts, ok := m.artifactsByModuleName[module.Name()]; ok {
+ m.artifacts = append(m.artifacts, artifacts...)
+ }
+ })
+}
+
+func (m *dexpreoptSystemserverCheck) MakeVars(ctx android.MakeVarsContext) {
+ ctx.Strict("DEXPREOPT_SYSTEMSERVER_ARTIFACTS", strings.Join(m.artifacts, " "))
+}
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index b13955fba..4d0bd09c6 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -32,7 +32,7 @@ func dexpreoptTargets(ctx android.PathContext) []android.Target {
}
}
// We may also need the images on host in order to run host-based tests.
- for _, target := range ctx.Config().Targets[android.BuildOs] {
+ for _, target := range ctx.Config().Targets[ctx.Config().BuildOS] {
targets = append(targets, target)
}
@@ -41,50 +41,59 @@ func dexpreoptTargets(ctx android.PathContext) []android.Target {
var (
bootImageConfigKey = android.NewOnceKey("bootImageConfig")
+ bootImageConfigRawKey = android.NewOnceKey("bootImageConfigRaw")
artBootImageName = "art"
frameworkBootImageName = "boot"
)
-// Construct the global boot image configs.
-func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
- return ctx.Config().Once(bootImageConfigKey, func() interface{} {
-
+func genBootImageConfigRaw(ctx android.PathContext) map[string]*bootImageConfig {
+ return ctx.Config().Once(bootImageConfigRawKey, func() interface{} {
global := dexpreopt.GetGlobalConfig(ctx)
- targets := dexpreoptTargets(ctx)
- deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
artModules := global.ArtApexJars
frameworkModules := global.BootJars.RemoveList(artModules)
- artDirOnHost := "apex/art_boot_images/javalib"
- artDirOnDevice := "apex/com.android.art/javalib"
- frameworkSubdir := "system/framework"
-
// ART config for the primary boot image in the ART apex.
// It includes the Core Libraries.
artCfg := bootImageConfig{
- name: artBootImageName,
- stem: "boot",
- installDirOnHost: artDirOnHost,
- installDirOnDevice: artDirOnDevice,
- modules: artModules,
+ name: artBootImageName,
+ stem: "boot",
+ installDirOnHost: "apex/art_boot_images/javalib",
+ installDirOnDevice: "system/framework",
+ profileInstallPathInApex: "etc/boot-image.prof",
+ modules: artModules,
+ preloadedClassesFile: "art/build/boot/preloaded-classes",
}
// Framework config for the boot image extension.
// It includes framework libraries and depends on the ART config.
+ frameworkSubdir := "system/framework"
frameworkCfg := bootImageConfig{
- extends: &artCfg,
- name: frameworkBootImageName,
- stem: "boot",
- installDirOnHost: frameworkSubdir,
- installDirOnDevice: frameworkSubdir,
- modules: frameworkModules,
+ extends: &artCfg,
+ name: frameworkBootImageName,
+ stem: "boot",
+ installDirOnHost: frameworkSubdir,
+ installDirOnDevice: frameworkSubdir,
+ modules: frameworkModules,
+ preloadedClassesFile: "frameworks/base/config/preloaded-classes",
}
- configs := map[string]*bootImageConfig{
+ return map[string]*bootImageConfig{
artBootImageName: &artCfg,
frameworkBootImageName: &frameworkCfg,
}
+ }).(map[string]*bootImageConfig)
+}
+
+// Construct the global boot image configs.
+func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
+ return ctx.Config().Once(bootImageConfigKey, func() interface{} {
+ targets := dexpreoptTargets(ctx)
+ deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
+
+ configs := genBootImageConfigRaw(ctx)
+ artCfg := configs[artBootImageName]
+ frameworkCfg := configs[frameworkBootImageName]
// common to all configs
for _, c := range configs {
@@ -142,14 +151,14 @@ func defaultBootImageConfig(ctx android.PathContext) *bootImageConfig {
return genBootImageConfigs(ctx)[frameworkBootImageName]
}
-// Updatable boot config allows to access build/install paths of updatable boot jars without going
+// Apex boot config allows to access build/install paths of apex boot jars without going
// through the usual trouble of registering dependencies on those modules and extracting build paths
// from those dependencies.
-type updatableBootConfig struct {
- // A list of updatable boot jars.
+type apexBootConfig struct {
+ // A list of apex boot jars.
modules android.ConfiguredJarList
- // A list of predefined build paths to updatable boot jars. They are configured very early,
+ // A list of predefined build paths to apex boot jars. They are configured very early,
// before the modules for these jars are processed and the actual paths are generated, and
// later on a singleton adds commands to copy actual jars to the predefined paths.
dexPaths android.WritablePaths
@@ -161,21 +170,21 @@ type updatableBootConfig struct {
dexLocations []string
}
-var updatableBootConfigKey = android.NewOnceKey("updatableBootConfig")
+var updatableBootConfigKey = android.NewOnceKey("apexBootConfig")
-// Returns updatable boot config.
-func GetUpdatableBootConfig(ctx android.PathContext) updatableBootConfig {
+// Returns apex boot config.
+func GetApexBootConfig(ctx android.PathContext) apexBootConfig {
return ctx.Config().Once(updatableBootConfigKey, func() interface{} {
- updatableBootJars := dexpreopt.GetGlobalConfig(ctx).UpdatableBootJars
+ apexBootJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
- dir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "updatable_bootjars")
- dexPaths := updatableBootJars.BuildPaths(ctx, dir)
- dexPathsByModuleName := updatableBootJars.BuildPathsByModule(ctx, dir)
+ dir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "apex_bootjars")
+ dexPaths := apexBootJars.BuildPaths(ctx, dir)
+ dexPathsByModuleName := apexBootJars.BuildPathsByModule(ctx, dir)
- dexLocations := updatableBootJars.DevicePaths(ctx.Config(), android.Android)
+ dexLocations := apexBootJars.DevicePaths(ctx.Config(), android.Android)
- return updatableBootConfig{updatableBootJars, dexPaths, dexPathsByModuleName, dexLocations}
- }).(updatableBootConfig)
+ return apexBootConfig{apexBootJars, dexPaths, dexPathsByModuleName, dexLocations}
+ }).(apexBootConfig)
}
// Returns a list of paths and a list of locations for the boot jars used in dexpreopt (to be
@@ -188,10 +197,10 @@ func bcpForDexpreopt(ctx android.PathContext, withUpdatable bool) (android.Writa
dexLocations := bootImage.getAnyAndroidVariant().dexLocationsDeps
if withUpdatable {
- // Updatable boot jars (they are used only in dexpreopt, but not in the boot image).
- updBootConfig := GetUpdatableBootConfig(ctx)
- dexPaths = append(dexPaths, updBootConfig.dexPaths...)
- dexLocations = append(dexLocations, updBootConfig.dexLocations...)
+ // Apex boot jars (they are used only in dexpreopt, but not in the boot image).
+ apexBootConfig := GetApexBootConfig(ctx)
+ dexPaths = append(dexPaths, apexBootConfig.dexPaths...)
+ dexLocations = append(dexLocations, apexBootConfig.dexLocations...)
}
return dexPaths, dexLocations
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index b25deceac..1c1070add 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -16,6 +16,8 @@ package java
import (
"fmt"
+ "runtime"
+ "strings"
"testing"
"android/soong/android"
@@ -23,11 +25,17 @@ import (
"android/soong/dexpreopt"
)
+func init() {
+ RegisterFakeRuntimeApexMutator()
+}
+
func TestDexpreoptEnabled(t *testing.T) {
tests := []struct {
- name string
- bp string
- enabled bool
+ name string
+ bp string
+ moduleName string
+ apexVariant bool
+ enabled bool
}{
{
name: "app",
@@ -147,13 +155,81 @@ func TestDexpreoptEnabled(t *testing.T) {
}`,
enabled: true,
},
+ {
+ name: "apex variant",
+ bp: `
+ java_library {
+ name: "foo",
+ installable: true,
+ srcs: ["a.java"],
+ apex_available: ["com.android.apex1"],
+ }`,
+ apexVariant: true,
+ enabled: false,
+ },
+ {
+ name: "apex variant of apex system server jar",
+ bp: `
+ java_library {
+ name: "service-foo",
+ installable: true,
+ srcs: ["a.java"],
+ apex_available: ["com.android.apex1"],
+ }`,
+ moduleName: "service-foo",
+ apexVariant: true,
+ enabled: true,
+ },
+ {
+ name: "apex variant of prebuilt apex system server jar",
+ bp: `
+ java_library {
+ name: "prebuilt_service-foo",
+ installable: true,
+ srcs: ["a.java"],
+ apex_available: ["com.android.apex1"],
+ }`,
+ moduleName: "prebuilt_service-foo",
+ apexVariant: true,
+ enabled: true,
+ },
+ {
+ name: "platform variant of apex system server jar",
+ bp: `
+ java_library {
+ name: "service-foo",
+ installable: true,
+ srcs: ["a.java"],
+ apex_available: ["com.android.apex1"],
+ }`,
+ moduleName: "service-foo",
+ apexVariant: false,
+ enabled: false,
+ },
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
- ctx, _ := testJava(t, test.bp)
+ preparers := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ PrepareForTestWithFakeApexMutator,
+ dexpreopt.FixtureSetApexSystemServerJars("com.android.apex1:service-foo"),
+ )
+
+ result := preparers.RunTestWithBp(t, test.bp)
+ ctx := result.TestContext
+
+ moduleName := "foo"
+ if test.moduleName != "" {
+ moduleName = test.moduleName
+ }
+
+ variant := "android_common"
+ if test.apexVariant {
+ variant += "_apex1000"
+ }
- dexpreopt := ctx.ModuleForTests("foo", "android_common").MaybeRule("dexpreopt")
+ dexpreopt := ctx.ModuleForTests(moduleName, variant).MaybeRule("dexpreopt")
enabled := dexpreopt.Rule != nil
if enabled != test.enabled {
@@ -173,9 +249,9 @@ func enabledString(enabled bool) string {
}
func TestDex2oatToolDeps(t *testing.T) {
- if android.BuildOs != android.Linux {
+ if runtime.GOOS != "linux" {
// The host binary paths checked below are build OS dependent.
- t.Skipf("Unsupported build OS %s", android.BuildOs)
+ t.Skipf("Unsupported build OS %s", runtime.GOOS)
}
preparers := android.GroupFixturePreparers(
@@ -219,3 +295,145 @@ func TestDex2oatToolDeps(t *testing.T) {
testDex2oatToolDep(true, true, true, prebuiltDex2oatPath)
testDex2oatToolDep(false, true, false, prebuiltDex2oatPath)
}
+
+func TestDexpreoptBuiltInstalledForApex(t *testing.T) {
+ preparers := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ PrepareForTestWithFakeApexMutator,
+ dexpreopt.FixtureSetApexSystemServerJars("com.android.apex1:service-foo"),
+ )
+
+ // An APEX system server jar.
+ result := preparers.RunTestWithBp(t, `
+ java_library {
+ name: "service-foo",
+ installable: true,
+ srcs: ["a.java"],
+ apex_available: ["com.android.apex1"],
+ }`)
+ ctx := result.TestContext
+ module := ctx.ModuleForTests("service-foo", "android_common_apex1000")
+ library := module.Module().(*Library)
+
+ installs := library.dexpreopter.DexpreoptBuiltInstalledForApex()
+
+ android.AssertIntEquals(t, "install count", 2, len(installs))
+
+ android.AssertStringEquals(t, "installs[0] FullModuleName",
+ "service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.odex",
+ installs[0].FullModuleName())
+
+ android.AssertStringEquals(t, "installs[0] SubModuleName",
+ "-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.odex",
+ installs[0].SubModuleName())
+
+ android.AssertStringEquals(t, "installs[1] FullModuleName",
+ "service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.vdex",
+ installs[1].FullModuleName())
+
+ android.AssertStringEquals(t, "installs[1] SubModuleName",
+ "-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.vdex",
+ installs[1].SubModuleName())
+
+ // Not an APEX system server jar.
+ result = preparers.RunTestWithBp(t, `
+ java_library {
+ name: "foo",
+ installable: true,
+ srcs: ["a.java"],
+ }`)
+ ctx = result.TestContext
+ module = ctx.ModuleForTests("foo", "android_common")
+ library = module.Module().(*Library)
+
+ installs = library.dexpreopter.DexpreoptBuiltInstalledForApex()
+
+ android.AssertIntEquals(t, "install count", 0, len(installs))
+}
+
+func filterDexpreoptEntriesList(entriesList []android.AndroidMkEntries) []android.AndroidMkEntries {
+ var results []android.AndroidMkEntries
+ for _, entries := range entriesList {
+ if strings.Contains(entries.EntryMap["LOCAL_MODULE"][0], "-dexpreopt-") {
+ results = append(results, entries)
+ }
+ }
+ return results
+}
+
+func verifyEntries(t *testing.T, message string, expectedModule string,
+ expectedPrebuiltModuleFile string, expectedModulePath string, expectedInstalledModuleStem string,
+ entries android.AndroidMkEntries) {
+ android.AssertStringEquals(t, message+" LOCAL_MODULE", expectedModule,
+ entries.EntryMap["LOCAL_MODULE"][0])
+
+ android.AssertStringEquals(t, message+" LOCAL_MODULE_CLASS", "ETC",
+ entries.EntryMap["LOCAL_MODULE_CLASS"][0])
+
+ android.AssertStringDoesContain(t, message+" LOCAL_PREBUILT_MODULE_FILE",
+ entries.EntryMap["LOCAL_PREBUILT_MODULE_FILE"][0], expectedPrebuiltModuleFile)
+
+ android.AssertStringDoesContain(t, message+" LOCAL_MODULE_PATH",
+ entries.EntryMap["LOCAL_MODULE_PATH"][0], expectedModulePath)
+
+ android.AssertStringEquals(t, message+" LOCAL_INSTALLED_MODULE_STEM",
+ expectedInstalledModuleStem, entries.EntryMap["LOCAL_INSTALLED_MODULE_STEM"][0])
+
+ android.AssertStringEquals(t, message+" LOCAL_NOT_AVAILABLE_FOR_PLATFORM",
+ "false", entries.EntryMap["LOCAL_NOT_AVAILABLE_FOR_PLATFORM"][0])
+}
+
+func TestAndroidMkEntriesForApex(t *testing.T) {
+ preparers := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ PrepareForTestWithFakeApexMutator,
+ dexpreopt.FixtureSetApexSystemServerJars("com.android.apex1:service-foo"),
+ )
+
+ // An APEX system server jar.
+ result := preparers.RunTestWithBp(t, `
+ java_library {
+ name: "service-foo",
+ installable: true,
+ srcs: ["a.java"],
+ apex_available: ["com.android.apex1"],
+ }`)
+ ctx := result.TestContext
+ module := ctx.ModuleForTests("service-foo", "android_common_apex1000")
+
+ entriesList := android.AndroidMkEntriesForTest(t, ctx, module.Module())
+ entriesList = filterDexpreoptEntriesList(entriesList)
+
+ android.AssertIntEquals(t, "entries count", 2, len(entriesList))
+
+ verifyEntries(t,
+ "entriesList[0]",
+ "service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.odex",
+ "/dexpreopt/oat/arm64/javalib.odex",
+ "/system/framework/oat/arm64",
+ "apex@com.android.apex1@javalib@service-foo.jar@classes.odex",
+ entriesList[0])
+
+ verifyEntries(t,
+ "entriesList[1]",
+ "service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.vdex",
+ "/dexpreopt/oat/arm64/javalib.vdex",
+ "/system/framework/oat/arm64",
+ "apex@com.android.apex1@javalib@service-foo.jar@classes.vdex",
+ entriesList[1])
+
+ // Not an APEX system server jar.
+ result = preparers.RunTestWithBp(t, `
+ java_library {
+ name: "foo",
+ installable: true,
+ srcs: ["a.java"],
+ }`)
+ ctx = result.TestContext
+ module = ctx.ModuleForTests("foo", "android_common")
+
+ entriesList = android.AndroidMkEntriesForTest(t, ctx, module.Module())
+ entriesList = filterDexpreoptEntriesList(entriesList)
+
+ android.AssertIntEquals(t, "entries count", 0, len(entriesList))
+}
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 869a5982d..023d61912 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -330,7 +330,7 @@ func (j *Javadoc) genSources(ctx android.ModuleContext, srcFiles android.Paths,
// Process all aidl files together to support sharding them into one or more rules that produce srcjars.
if len(aidlSrcs) > 0 {
- srcJarFiles := genAidl(ctx, aidlSrcs, flags.aidlFlags+aidlIncludeFlags, flags.aidlDeps)
+ srcJarFiles := genAidl(ctx, aidlSrcs, flags.aidlFlags+aidlIncludeFlags, nil, flags.aidlDeps)
outSrcFiles = append(outSrcFiles, srcJarFiles...)
}
@@ -769,8 +769,8 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
d.Javadoc.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip")
- jsilver := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jsilver.jar")
- doclava := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "doclava.jar")
+ jsilver := ctx.Config().HostJavaToolPath(ctx, "jsilver.jar")
+ doclava := ctx.Config().HostJavaToolPath(ctx, "doclava.jar")
outDir := android.PathForModuleOut(ctx, "out")
srcJarDir := android.PathForModuleOut(ctx, "srcjars")
diff --git a/java/droidstubs.go b/java/droidstubs.go
index c756815c6..3b1f7c041 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -16,6 +16,7 @@ package java
import (
"fmt"
+ "path/filepath"
"strings"
"github.com/google/blueprint/proptools"
@@ -25,6 +26,9 @@ import (
"android/soong/remoteexec"
)
+// The values allowed for Droidstubs' Api_levels_sdk_type
+var allowedApiLevelSdkTypes = []string{"public", "system", "module-lib"}
+
func init() {
RegisterStubsBuildComponents(android.InitRegistrationContext)
}
@@ -128,12 +132,15 @@ type DroidstubsProperties struct {
// whicih can be used for scheduling purposes
High_mem *bool
- // is set to true, Metalava will allow framework SDK to contain API levels annotations.
+ // if set to true, Metalava will allow framework SDK to contain API levels annotations.
Api_levels_annotations_enabled *bool
// the dirs which Metalava extracts API levels annotations from.
Api_levels_annotations_dirs []string
+ // the sdk kind which Metalava extracts API levels annotations from. Supports 'public', 'system' and 'module-lib' for now; defaults to public.
+ Api_levels_sdk_type *string
+
// the filename which Metalava extracts API levels annotations from. Defaults to android.jar.
Api_levels_jar_filename *string
@@ -153,6 +160,7 @@ type ApiStubsSrcProvider interface {
// Provider of information about API stubs, used by java_sdk_library.
type ApiStubsProvider interface {
+ AnnotationsZip() android.Path
ApiFilePath
RemovedApiFilePath() android.Path
@@ -207,6 +215,10 @@ func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) {
}
}
+func (d *Droidstubs) AnnotationsZip() android.Path {
+ return d.annotationsZip
+}
+
func (d *Droidstubs) ApiFilePath() android.Path {
return d.apiFilePath
}
@@ -322,7 +334,11 @@ func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.Ru
// TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
cmd.FlagWithArg("--hide ", "HiddenTypedefConstant").
FlagWithArg("--hide ", "SuperfluousPrefix").
- FlagWithArg("--hide ", "AnnotationExtraction")
+ FlagWithArg("--hide ", "AnnotationExtraction").
+ // b/222738070
+ FlagWithArg("--hide ", "BannedThrow").
+ // b/223382732
+ FlagWithArg("--hide ", "ChangedDefault")
}
}
@@ -367,6 +383,7 @@ func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *a
filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar")
+ var dirs []string
ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
if t, ok := m.(*ExportedDroiddocDir); ok {
for _, dep := range t.deps {
@@ -383,12 +400,41 @@ func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *a
cmd.Implicit(dep)
}
}
- cmd.FlagWithArg("--android-jar-pattern ", t.dir.String()+"/%/public/"+filename)
+
+ dirs = append(dirs, t.dir.String())
} else {
ctx.PropertyErrorf("api_levels_annotations_dirs",
"module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
}
})
+
+ // Add all relevant --android-jar-pattern patterns for Metalava.
+ // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines
+ // an actual file present on disk (in the order the patterns were passed). For system APIs for
+ // privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs
+ // for older releases. Similarly, module-lib falls back to system API.
+ var sdkDirs []string
+ switch proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") {
+ case "module-lib":
+ sdkDirs = []string{"module-lib", "system", "public"}
+ case "system":
+ sdkDirs = []string{"system", "public"}
+ case "public":
+ sdkDirs = []string{"public"}
+ default:
+ ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes)
+ return
+ }
+
+ for _, sdkDir := range sdkDirs {
+ for _, dir := range dirs {
+ cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, filename))
+ }
+ }
+}
+
+func metalavaUseRbe(ctx android.ModuleContext) bool {
+ return ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA")
}
func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
@@ -399,7 +445,7 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi
cmd := rule.Command()
cmd.FlagWithArg("ANDROID_PREFS_ROOT=", homeDir.String())
- if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA") {
+ if metalavaUseRbe(ctx) {
rule.Remoteable(android.RemoteRuleSupports{RBE: true})
execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
labels := map[string]string{"type": "tool", "name": "metalava"}
@@ -434,7 +480,10 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi
Flag("--quiet").
Flag("--format=v2").
FlagWithArg("--repeat-errors-max ", "10").
- FlagWithArg("--hide ", "UnresolvedImport")
+ FlagWithArg("--hide ", "UnresolvedImport").
+ FlagWithArg("--hide ", "InvalidNullabilityOverride").
+ // b/223382732
+ FlagWithArg("--hide ", "ChangedDefault")
return cmd
}
@@ -530,7 +579,8 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
`\n` +
`If it is not possible to do so, there are workarounds:\n` +
`\n` +
- `1. You can suppress the errors with @SuppressLint("<id>")\n`
+ `1. You can suppress the errors with @SuppressLint("<id>")\n` +
+ ` where the <id> is given in brackets in the error message above.\n`
if baselineFile.Valid() {
cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
@@ -619,7 +669,9 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
// TODO(b/183630617): rewrapper doesn't support restat rules
- // rule.Restat()
+ if !metalavaUseRbe(ctx) {
+ rule.Restat()
+ }
zipSyncCleanupCmd(rule, srcJarDir)
@@ -767,7 +819,7 @@ type PrebuiltStubsSources struct {
properties PrebuiltStubsSourcesProperties
- stubsSrcJar android.ModuleOutPath
+ stubsSrcJar android.Path
}
func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
@@ -784,35 +836,39 @@ func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
}
func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- p.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
-
if len(p.properties.Srcs) != 1 {
- ctx.PropertyErrorf("srcs", "must only specify one directory path, contains %d paths", len(p.properties.Srcs))
+ ctx.PropertyErrorf("srcs", "must only specify one directory path or srcjar, contains %d paths", len(p.properties.Srcs))
return
}
- localSrcDir := p.properties.Srcs[0]
- // Although PathForModuleSrc can return nil if either the path doesn't exist or
- // the path components are invalid it won't in this case because no components
- // are specified and the module directory must exist in order to get this far.
- srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, localSrcDir)
-
- // Glob the contents of the directory just in case the directory does not exist.
- srcGlob := localSrcDir + "/**/*"
- srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
+ src := p.properties.Srcs[0]
+ if filepath.Ext(src) == ".srcjar" {
+ // This is a srcjar. We can use it directly.
+ p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
+ } else {
+ outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
- rule := android.NewRuleBuilder(pctx, ctx)
- rule.Command().
- BuiltTool("soong_zip").
- Flag("-write_if_changed").
- Flag("-jar").
- FlagWithOutput("-o ", p.stubsSrcJar).
- FlagWithArg("-C ", srcDir.String()).
- FlagWithRspFileInputList("-r ", p.stubsSrcJar.ReplaceExtension(ctx, "rsp"), srcPaths)
+ // This is a directory. Glob the contents just in case the directory does not exist.
+ srcGlob := src + "/**/*"
+ srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
- rule.Restat()
+ // Although PathForModuleSrc can return nil if either the path doesn't exist or
+ // the path components are invalid it won't in this case because no components
+ // are specified and the module directory must exist in order to get this far.
+ srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src)
- rule.Build("zip src", "Create srcjar from prebuilt source")
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ BuiltTool("soong_zip").
+ Flag("-write_if_changed").
+ Flag("-jar").
+ FlagWithOutput("-o ", outPath).
+ FlagWithArg("-C ", srcDir.String()).
+ FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths)
+ rule.Restat()
+ rule.Build("zip src", "Create srcjar from prebuilt source")
+ p.stubsSrcJar = outPath
+ }
}
func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go
index db664c15e..10d99f3a5 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -15,7 +15,9 @@
package java
import (
+ "fmt"
"reflect"
+ "regexp"
"strings"
"testing"
@@ -81,6 +83,75 @@ func TestDroidstubs(t *testing.T) {
}
}
+// runs a test for droidstubs with a customizable sdkType argument and returns
+// the list of jar patterns that is passed as `--android-jar-pattern`
+func getAndroidJarPatternsForDroidstubs(t *testing.T, sdkType string) []string {
+ ctx, _ := testJavaWithFS(t, fmt.Sprintf(`
+ droiddoc_exported_dir {
+ name: "some-exported-dir",
+ path: "somedir",
+ }
+
+ droiddoc_exported_dir {
+ name: "some-other-exported-dir",
+ path: "someotherdir",
+ }
+
+ droidstubs {
+ name: "foo-stubs",
+ srcs: ["foo-doc/a.java"],
+ api_levels_annotations_dirs: [
+ "some-exported-dir",
+ "some-other-exported-dir",
+ ],
+ api_levels_annotations_enabled: true,
+ api_levels_sdk_type: "%s",
+ }
+ `, sdkType),
+ map[string][]byte{
+ "foo-doc/a.java": nil,
+ })
+
+ m := ctx.ModuleForTests("foo-stubs", "android_common")
+ manifest := m.Output("metalava.sbox.textproto")
+ cmd := String(android.RuleBuilderSboxProtoForTests(t, manifest).Commands[0].Command)
+ r := regexp.MustCompile(`--android-jar-pattern [^ ]+/android.jar`)
+ return r.FindAllString(cmd, -1)
+}
+
+func TestPublicDroidstubs(t *testing.T) {
+ patterns := getAndroidJarPatternsForDroidstubs(t, "public")
+
+ android.AssertArrayString(t, "order of patterns", []string{
+ "--android-jar-pattern somedir/%/public/android.jar",
+ "--android-jar-pattern someotherdir/%/public/android.jar",
+ }, patterns)
+}
+
+func TestSystemDroidstubs(t *testing.T) {
+ patterns := getAndroidJarPatternsForDroidstubs(t, "system")
+
+ android.AssertArrayString(t, "order of patterns", []string{
+ "--android-jar-pattern somedir/%/system/android.jar",
+ "--android-jar-pattern someotherdir/%/system/android.jar",
+ "--android-jar-pattern somedir/%/public/android.jar",
+ "--android-jar-pattern someotherdir/%/public/android.jar",
+ }, patterns)
+}
+
+func TestModuleLibDroidstubs(t *testing.T) {
+ patterns := getAndroidJarPatternsForDroidstubs(t, "module-lib")
+
+ android.AssertArrayString(t, "order of patterns", []string{
+ "--android-jar-pattern somedir/%/module-lib/android.jar",
+ "--android-jar-pattern someotherdir/%/module-lib/android.jar",
+ "--android-jar-pattern somedir/%/system/android.jar",
+ "--android-jar-pattern someotherdir/%/system/android.jar",
+ "--android-jar-pattern somedir/%/public/android.jar",
+ "--android-jar-pattern someotherdir/%/public/android.jar",
+ }, patterns)
+}
+
func TestDroidstubsSandbox(t *testing.T) {
ctx, _ := testJavaWithFS(t, `
genrule {
diff --git a/java/fuzz.go b/java/fuzz.go
new file mode 100644
index 000000000..257f34356
--- /dev/null
+++ b/java/fuzz.go
@@ -0,0 +1,159 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "github.com/google/blueprint/proptools"
+ "sort"
+ "strings"
+
+ "android/soong/android"
+ "android/soong/fuzz"
+)
+
+func init() {
+ RegisterJavaFuzzBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterJavaFuzzBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("java_fuzz_host", FuzzFactory)
+ ctx.RegisterSingletonType("java_fuzz_packaging", javaFuzzPackagingFactory)
+}
+
+type JavaFuzzLibrary struct {
+ Library
+ fuzzPackagedModule fuzz.FuzzPackagedModule
+}
+
+func (j *JavaFuzzLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ j.Library.GenerateAndroidBuildActions(ctx)
+
+ if j.fuzzPackagedModule.FuzzProperties.Corpus != nil {
+ j.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, j.fuzzPackagedModule.FuzzProperties.Corpus)
+ }
+ if j.fuzzPackagedModule.FuzzProperties.Data != nil {
+ j.fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, j.fuzzPackagedModule.FuzzProperties.Data)
+ }
+ if j.fuzzPackagedModule.FuzzProperties.Dictionary != nil {
+ j.fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *j.fuzzPackagedModule.FuzzProperties.Dictionary)
+ }
+
+ if j.fuzzPackagedModule.FuzzProperties.Fuzz_config != nil {
+ configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json")
+ android.WriteFileRule(ctx, configPath, j.fuzzPackagedModule.FuzzProperties.Fuzz_config.String())
+ j.fuzzPackagedModule.Config = configPath
+ }
+}
+
+// java_fuzz builds and links sources into a `.jar` file for the host.
+//
+// By default, a java_fuzz produces a `.jar` file containing `.class` files.
+// This jar is not suitable for installing on a device.
+func FuzzFactory() android.Module {
+ module := &JavaFuzzLibrary{}
+
+ module.addHostProperties()
+ module.Module.properties.Installable = proptools.BoolPtr(false)
+ module.AddProperties(&module.fuzzPackagedModule.FuzzProperties)
+
+ // java_fuzz packaging rules collide when both linux_glibc and linux_bionic are enabled, disable the linux_bionic variants.
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ disableLinuxBionic := struct {
+ Target struct {
+ Linux_bionic struct {
+ Enabled *bool
+ }
+ }
+ }{}
+ disableLinuxBionic.Target.Linux_bionic.Enabled = proptools.BoolPtr(false)
+ ctx.AppendProperties(&disableLinuxBionic)
+ })
+
+ module.initModuleAndImport(module)
+ android.InitSdkAwareModule(module)
+ InitJavaModule(module, android.HostSupported)
+ return module
+}
+
+// Responsible for generating rules that package fuzz targets into
+// their architecture & target/host specific zip file.
+type javaFuzzPackager struct {
+ fuzz.FuzzPackager
+}
+
+func javaFuzzPackagingFactory() android.Singleton {
+ return &javaFuzzPackager{}
+}
+
+func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
+ // Map between each architecture + host/device combination.
+ archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip)
+
+ // List of individual fuzz targets.
+ s.FuzzTargets = make(map[string]bool)
+
+ ctx.VisitAllModules(func(module android.Module) {
+ // Discard non-fuzz targets.
+ javaModule, ok := module.(*JavaFuzzLibrary)
+ if !ok {
+ return
+ }
+
+ fuzzModuleValidator := fuzz.FuzzModule{
+ javaModule.ModuleBase,
+ javaModule.DefaultableModuleBase,
+ javaModule.ApexModuleBase,
+ }
+
+ if ok := fuzz.IsValid(fuzzModuleValidator); !ok || *javaModule.Module.properties.Installable {
+ return
+ }
+
+ hostOrTargetString := "target"
+ if javaModule.Host() {
+ hostOrTargetString = "host"
+ }
+ archString := javaModule.Arch().ArchType.String()
+
+ archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
+ archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
+
+ var files []fuzz.FileToZip
+ builder := android.NewRuleBuilder(pctx, ctx)
+
+ // Package the artifacts (data, corpus, config and dictionary into a zipfile.
+ files = s.PackageArtifacts(ctx, module, javaModule.fuzzPackagedModule, archDir, builder)
+
+ // Add .jar
+ files = append(files, fuzz.FileToZip{javaModule.outputFile, ""})
+
+ archDirs[archOs], ok = s.BuildZipFile(ctx, module, javaModule.fuzzPackagedModule, files, builder, archDir, archString, "host", archOs, archDirs)
+ if !ok {
+ return
+ }
+
+ })
+ s.CreateFuzzPackage(ctx, archDirs, fuzz.Java, pctx)
+}
+
+func (s *javaFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
+ packages := s.Packages.Strings()
+ sort.Strings(packages)
+
+ ctx.Strict("SOONG_JAVA_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(packages, " "))
+
+ // Preallocate the slice of fuzz targets to minimize memory allocations.
+ s.PreallocateSlice(ctx, "ALL_JAVA_FUZZ_TARGETS")
+}
diff --git a/java/fuzz_test.go b/java/fuzz_test.go
new file mode 100644
index 000000000..cf063ebe2
--- /dev/null
+++ b/java/fuzz_test.go
@@ -0,0 +1,65 @@
+// Copyright 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "android/soong/android"
+ "path/filepath"
+ "testing"
+)
+
+var prepForJavaFuzzTest = android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.FixtureRegisterWithContext(RegisterJavaFuzzBuildComponents),
+)
+
+func TestJavaFuzz(t *testing.T) {
+ result := prepForJavaFuzzTest.RunTestWithBp(t, `
+ java_fuzz_host {
+ name: "foo",
+ srcs: ["a.java"],
+ libs: ["bar"],
+ static_libs: ["baz"],
+ }
+
+ java_library_host {
+ name: "bar",
+ srcs: ["b.java"],
+ }
+
+ java_library_host {
+ name: "baz",
+ srcs: ["c.java"],
+ }`)
+
+ osCommonTarget := result.Config.BuildOSCommonTarget.String()
+ javac := result.ModuleForTests("foo", osCommonTarget).Rule("javac")
+ combineJar := result.ModuleForTests("foo", osCommonTarget).Description("for javac")
+
+ if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
+ t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
+ }
+
+ baz := result.ModuleForTests("baz", osCommonTarget).Rule("javac").Output.String()
+ barOut := filepath.Join("out", "soong", ".intermediates", "bar", osCommonTarget, "javac", "bar.jar")
+ bazOut := filepath.Join("out", "soong", ".intermediates", "baz", osCommonTarget, "javac", "baz.jar")
+
+ android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], barOut)
+ android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], bazOut)
+
+ if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
+ t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
+ }
+}
diff --git a/java/gen.go b/java/gen.go
index 445a2d8a3..1572bf00a 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -44,7 +44,7 @@ var (
})
)
-func genAidl(ctx android.ModuleContext, aidlFiles android.Paths, aidlFlags string, deps android.Paths) android.Paths {
+func genAidl(ctx android.ModuleContext, aidlFiles android.Paths, aidlGlobalFlags string, aidlIndividualFlags map[string]string, deps android.Paths) android.Paths {
// Shard aidl files into groups of 50 to avoid having to recompile all of them if one changes and to avoid
// hitting command line length limits.
shards := android.ShardPaths(aidlFiles, 50)
@@ -61,15 +61,17 @@ func genAidl(ctx android.ModuleContext, aidlFiles android.Paths, aidlFlags strin
rule.Command().Text("rm -rf").Flag(outDir.String())
rule.Command().Text("mkdir -p").Flag(outDir.String())
- rule.Command().Text("FLAGS=' " + aidlFlags + "'")
+ rule.Command().Text("FLAGS=' " + aidlGlobalFlags + "'")
for _, aidlFile := range shard {
+ localFlag := aidlIndividualFlags[aidlFile.String()]
depFile := srcJarFile.InSameDir(ctx, aidlFile.String()+".d")
javaFile := outDir.Join(ctx, pathtools.ReplaceExtension(aidlFile.String(), "java"))
rule.Command().
Tool(ctx.Config().HostToolPath(ctx, "aidl")).
FlagWithDepFile("-d", depFile).
Flag("$FLAGS").
+ Flag(localFlag).
Input(aidlFile).
Output(javaFile).
Implicits(deps)
@@ -159,7 +161,14 @@ func (j *Module) genSources(ctx android.ModuleContext, srcFiles android.Paths,
// Process all aidl files together to support sharding them into one or more rules that produce srcjars.
if len(aidlSrcs) > 0 {
- srcJarFiles := genAidl(ctx, aidlSrcs, flags.aidlFlags+aidlIncludeFlags, flags.aidlDeps)
+ individualFlags := make(map[string]string)
+ for _, aidlSrc := range aidlSrcs {
+ flags := j.individualAidlFlags(ctx, aidlSrc)
+ if flags != "" {
+ individualFlags[aidlSrc.String()] = flags
+ }
+ }
+ srcJarFiles := genAidl(ctx, aidlSrcs, flags.aidlFlags+aidlIncludeFlags, individualFlags, flags.aidlDeps)
outSrcFiles = append(outSrcFiles, srcJarFiles...)
}
diff --git a/java/genrule.go b/java/genrule.go
index e0a9c8faf..5047c412f 100644
--- a/java/genrule.go
+++ b/java/genrule.go
@@ -24,8 +24,8 @@ func init() {
}
func RegisterGenRuleBuildComponents(ctx android.RegistrationContext) {
- ctx.RegisterModuleType("java_genrule", genRuleFactory)
- ctx.RegisterModuleType("java_genrule_host", genRuleFactoryHost)
+ ctx.RegisterModuleType("java_genrule", GenRuleFactory)
+ ctx.RegisterModuleType("java_genrule_host", GenRuleFactoryHost)
}
// java_genrule is a genrule that can depend on other java_* objects.
@@ -33,7 +33,7 @@ func RegisterGenRuleBuildComponents(ctx android.RegistrationContext) {
// By default a java_genrule has a single variant that will run against the device variant of its dependencies and
// produce an output that can be used as an input to a device java rule.
//
-// Specifying `host_supported: true` will produce two variants, one that uses device dependencie sand one that uses
+// Specifying `host_supported: true` will produce two variants, one that uses device dependencies and one that uses
// host dependencies. Each variant will run the command.
//
// Use a java_genrule instead of a genrule when it needs to depend on or be depended on by other java modules, unless
@@ -44,7 +44,7 @@ func RegisterGenRuleBuildComponents(ctx android.RegistrationContext) {
// Use a java_genrule to package generated java resources:
//
// java_genrule {
-// name: "generated_resources",
+// name: "generated_resources",
// tools: [
// "generator",
// "soong_zip",
@@ -60,10 +60,12 @@ func RegisterGenRuleBuildComponents(ctx android.RegistrationContext) {
// srcs: ["src/**/*.java"],
// static_libs: ["generated_resources"],
// }
-func genRuleFactory() android.Module {
+func GenRuleFactory() android.Module {
module := genrule.NewGenRule()
android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ android.InitBazelModule(module)
return module
}
@@ -72,10 +74,12 @@ func genRuleFactory() android.Module {
//
// A java_genrule_host has a single variant that will run against the host variant of its dependencies and
// produce an output that can be used as an input to a host java rule.
-func genRuleFactoryHost() android.Module {
+func GenRuleFactoryHost() android.Module {
module := genrule.NewGenRule()
android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
+ android.InitBazelModule(module)
return module
}
diff --git a/java/genrule_test.go b/java/genrule_test.go
new file mode 100644
index 000000000..1c294b286
--- /dev/null
+++ b/java/genrule_test.go
@@ -0,0 +1,118 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+
+ "android/soong/android"
+)
+
+func testGenruleContext(config android.Config) *android.TestContext {
+ ctx := android.NewTestArchContext(config)
+ ctx.RegisterModuleType("java_genrule", GenRuleFactory)
+ ctx.Register()
+
+ return ctx
+}
+
+func TestGenruleCmd(t *testing.T) {
+ fs := map[string][]byte{
+ "tool": nil,
+ "foo": nil,
+ }
+ bp := `
+ java_genrule {
+ name: "gen",
+ tool_files: ["tool"],
+ cmd: "$(location tool) $(in) $(out)",
+ srcs: ["foo"],
+ out: ["out"],
+ }
+ `
+ config := android.TestArchConfig(t.TempDir(), nil, bp, fs)
+
+ ctx := testGenruleContext(config)
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ if errs == nil {
+ _, errs = ctx.PrepareBuildActions(config)
+ }
+ if errs != nil {
+ t.Fatal(errs)
+ }
+
+ gen := ctx.ModuleForTests("gen", "android_common").Output("out")
+ expected := []string{"foo"}
+ if !reflect.DeepEqual(expected, gen.Implicits.Strings()[:len(expected)]) {
+ t.Errorf(`want arm inputs %v, got %v`, expected, gen.Implicits.Strings())
+ }
+}
+
+func TestJarGenrules(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ }
+
+ java_genrule {
+ name: "jargen",
+ tool_files: ["b.java"],
+ cmd: "$(location b.java) $(in) $(out)",
+ out: ["jargen.jar"],
+ srcs: [":foo"],
+ }
+
+ java_library {
+ name: "bar",
+ static_libs: ["jargen"],
+ srcs: ["c.java"],
+ }
+
+ java_library {
+ name: "baz",
+ libs: ["jargen"],
+ srcs: ["c.java"],
+ }
+ `)
+
+ foo := ctx.ModuleForTests("foo", "android_common").Output("javac/foo.jar")
+ jargen := ctx.ModuleForTests("jargen", "android_common").Output("jargen.jar")
+ bar := ctx.ModuleForTests("bar", "android_common").Output("javac/bar.jar")
+ baz := ctx.ModuleForTests("baz", "android_common").Output("javac/baz.jar")
+ barCombined := ctx.ModuleForTests("bar", "android_common").Output("combined/bar.jar")
+
+ if g, w := jargen.Implicits.Strings(), foo.Output.String(); !android.InList(w, g) {
+ t.Errorf("expected jargen inputs [%q], got %q", w, g)
+ }
+
+ if !strings.Contains(bar.Args["classpath"], jargen.Output.String()) {
+ t.Errorf("bar classpath %v does not contain %q", bar.Args["classpath"], jargen.Output.String())
+ }
+
+ if !strings.Contains(baz.Args["classpath"], jargen.Output.String()) {
+ t.Errorf("baz classpath %v does not contain %q", baz.Args["classpath"], jargen.Output.String())
+ }
+
+ if len(barCombined.Inputs) != 2 ||
+ barCombined.Inputs[0].String() != bar.Output.String() ||
+ barCombined.Inputs[1].String() != jargen.Output.String() {
+ t.Errorf("bar combined jar inputs %v is not [%q, %q]",
+ barCombined.Inputs.Strings(), bar.Output.String(), jargen.Output.String())
+ }
+}
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index f901434a0..cf9c7ad7a 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -30,14 +30,14 @@ type hiddenAPI struct {
// that information encoded within it.
active bool
- // The path to the dex jar that is in the boot class path. If this is nil then the associated
+ // The path to the dex jar that is in the boot class path. If this is unset then the associated
// module is not a boot jar, but could be one of the <x>-hiddenapi modules that provide additional
// annotations for the <x> boot dex jar but which do not actually provide a boot dex jar
// themselves.
//
// This must be the path to the unencoded dex jar as the encoded dex jar indirectly depends on
// this file so using the encoded dex jar here would result in a cycle in the ninja rules.
- bootDexJarPath android.Path
+ bootDexJarPath OptionalDexJarPath
// The paths to the classes jars that contain classes and class members annotated with
// the UnsupportedAppUsage annotation that need to be extracted as part of the hidden API
@@ -49,7 +49,7 @@ type hiddenAPI struct {
uncompressDexState *bool
}
-func (h *hiddenAPI) bootDexJar() android.Path {
+func (h *hiddenAPI) bootDexJar() OptionalDexJarPath {
return h.bootDexJarPath
}
@@ -65,10 +65,12 @@ func (h *hiddenAPI) uncompressDex() *bool {
type hiddenAPIModule interface {
android.Module
hiddenAPIIntf
+
+ MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec
}
type hiddenAPIIntf interface {
- bootDexJar() android.Path
+ bootDexJar() OptionalDexJarPath
classesJars() android.Paths
uncompressDex() *bool
}
@@ -79,7 +81,7 @@ var _ hiddenAPIIntf = (*hiddenAPI)(nil)
//
// uncompressedDexState should be nil when the module is a prebuilt and so does not require hidden
// API encoding.
-func (h *hiddenAPI) initHiddenAPI(ctx android.ModuleContext, dexJar, classesJar android.Path, uncompressedDexState *bool) {
+func (h *hiddenAPI) initHiddenAPI(ctx android.ModuleContext, dexJar OptionalDexJarPath, classesJar android.Path, uncompressedDexState *bool) {
// Save the classes jars even if this is not active as they may be used by modular hidden API
// processing.
@@ -118,11 +120,11 @@ func (h *hiddenAPI) initHiddenAPI(ctx android.ModuleContext, dexJar, classesJar
}
func isModuleInBootClassPath(ctx android.BaseModuleContext, module android.Module) bool {
- // Get the configured non-updatable and updatable boot jars.
- nonUpdatableBootJars := ctx.Config().NonUpdatableBootJars()
- updatableBootJars := ctx.Config().UpdatableBootJars()
- active := isModuleInConfiguredList(ctx, module, nonUpdatableBootJars) ||
- isModuleInConfiguredList(ctx, module, updatableBootJars)
+ // Get the configured platform and apex boot jars.
+ nonApexBootJars := ctx.Config().NonApexBootJars()
+ apexBootJars := ctx.Config().ApexBootJars()
+ active := isModuleInConfiguredList(ctx, module, nonApexBootJars) ||
+ isModuleInConfiguredList(ctx, module, apexBootJars)
return active
}
@@ -148,7 +150,7 @@ func (h *hiddenAPI) hiddenAPIEncodeDex(ctx android.ModuleContext, dexJar android
// Create a copy of the dex jar which has been encoded with hiddenapi flags.
flagsCSV := hiddenAPISingletonPaths(ctx).flags
outputDir := android.PathForModuleOut(ctx, "hiddenapi").OutputPath
- encodedDex := hiddenAPIEncodeDex(ctx, dexJar, flagsCSV, uncompressDex, outputDir)
+ encodedDex := hiddenAPIEncodeDex(ctx, dexJar, flagsCSV, uncompressDex, android.SdkSpecNone, outputDir)
// Use the encoded dex jar from here onwards.
return encodedDex
@@ -246,7 +248,7 @@ var hiddenAPIEncodeDexRule = pctx.AndroidStaticRule("hiddenAPIEncodeDex", bluepr
// The encode dex rule requires unzipping, encoding and rezipping the classes.dex files along with
// all the resources from the input jar. It also ensures that if it was uncompressed in the input
// it stays uncompressed in the output.
-func hiddenAPIEncodeDex(ctx android.ModuleContext, dexInput, flagsCSV android.Path, uncompressDex bool, outputDir android.OutputPath) android.OutputPath {
+func hiddenAPIEncodeDex(ctx android.ModuleContext, dexInput, flagsCSV android.Path, uncompressDex bool, minSdkVersion android.SdkSpec, outputDir android.OutputPath) android.OutputPath {
// The output file has the same name as the input file and is in the output directory.
output := outputDir.Join(ctx, dexInput.Base())
@@ -274,6 +276,15 @@ func hiddenAPIEncodeDex(ctx android.ModuleContext, dexInput, flagsCSV android.Pa
hiddenapiFlags = "--no-force-assign-all"
}
+ // If the library is targeted for Q and/or R then make sure that they do not
+ // have any S+ flags encoded as that will break the runtime.
+ minApiLevel := minSdkVersion.ApiLevel
+ if !minApiLevel.IsNone() {
+ if minApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(ctx, "R")) {
+ hiddenapiFlags = hiddenapiFlags + " --max-hiddenapi-level=max-target-r"
+ }
+ }
+
ctx.Build(pctx, android.BuildParams{
Rule: hiddenAPIEncodeDexRule,
Description: "hiddenapi encode dex",
@@ -297,6 +308,7 @@ func hiddenAPIEncodeDex(ctx android.ModuleContext, dexInput, flagsCSV android.Pa
type hiddenApiAnnotationsDependencyTag struct {
blueprint.BaseDependencyTag
+ android.LicenseAnnotationSharedDependencyTag
}
// Tag used to mark dependencies on java_library instances that contains Java source files whose
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 654ebb743..c90b2ff97 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -19,6 +19,7 @@ import (
"strings"
"android/soong/android"
+
"github.com/google/blueprint"
)
@@ -218,7 +219,7 @@ func (b hiddenAPIStubsDependencyTag) ExcludeFromVisibilityEnforcement() {
var _ android.ExcludeFromVisibilityEnforcementTag = hiddenAPIStubsDependencyTag{}
var _ android.ReplaceSourceWithPrebuilt = hiddenAPIStubsDependencyTag{}
var _ android.ExcludeFromApexContentsTag = hiddenAPIStubsDependencyTag{}
-var _ android.SdkMemberTypeDependencyTag = hiddenAPIStubsDependencyTag{}
+var _ android.SdkMemberDependencyTag = hiddenAPIStubsDependencyTag{}
// hiddenAPIComputeMonolithicStubLibModules computes the set of module names that provide stubs
// needed to produce the hidden API monolithic stub flags file.
@@ -277,7 +278,7 @@ func hiddenAPIAddStubLibDependencies(ctx android.BottomUpMutatorContext, apiScop
// hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if
// available, or reports an error.
func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path {
- var dexJar android.Path
+ var dexJar OptionalDexJarPath
if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
dexJar = sdkLibrary.SdkApiStubDexJar(ctx, kind)
} else if j, ok := module.(UsesLibraryDependency); ok {
@@ -287,17 +288,24 @@ func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.
return nil
}
- if dexJar == nil {
- ctx.ModuleErrorf("dependency %s does not provide a dex jar, consider setting compile_dex: true", module)
+ if !dexJar.Valid() {
+ ctx.ModuleErrorf("dependency %s does not provide a dex jar: %s", module, dexJar.InvalidReason())
+ return nil
}
- return dexJar
+ return dexJar.Path()
}
+// HIDDENAPI_STUB_FLAGS_IMPL_FLAGS is the set of flags that identify implementation only signatures,
+// i.e. those signatures that are not part of any API (including the hidden API).
+var HIDDENAPI_STUB_FLAGS_IMPL_FLAGS = []string{}
+
+var HIDDENAPI_FLAGS_CSV_IMPL_FLAGS = []string{"blocked"}
+
// buildRuleToGenerateHiddenAPIStubFlagsFile creates a rule to create a hidden API stub flags file.
//
// The rule is initialized but not built so that the caller can modify it and select an appropriate
// name.
-func buildRuleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, name, desc string, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput, moduleStubFlagsPaths android.Paths) {
+func buildRuleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, name, desc string, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput, stubFlagSubsets SignatureCsvSubsets) {
// Singleton rule which applies hiddenapi on all boot class path dex files.
rule := android.NewRuleBuilder(pctx, ctx)
@@ -317,7 +325,7 @@ func buildRuleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, name,
// If no module stub flags paths are provided then this must be being called for a
// bootclasspath_fragment and not the whole platform_bootclasspath.
- if moduleStubFlagsPaths == nil {
+ if stubFlagSubsets == nil {
// This is being run on a fragment of the bootclasspath.
command.Flag("--fragment")
}
@@ -342,8 +350,9 @@ func buildRuleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, name,
// If there are stub flag files that have been generated by fragments on which this depends then
// use them to validate the stub flag file generated by the rules created by this method.
- if len(moduleStubFlagsPaths) > 0 {
- validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, moduleStubFlagsPaths)
+ if len(stubFlagSubsets) > 0 {
+ validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, stubFlagSubsets,
+ HIDDENAPI_STUB_FLAGS_IMPL_FLAGS)
// Add the file that indicates that the file generated by this is valid.
//
@@ -510,14 +519,6 @@ func (s FlagFilesByCategory) append(other FlagFilesByCategory) {
}
}
-// dedup removes duplicates in the flag files, while maintaining the order in which they were
-// appended.
-func (s FlagFilesByCategory) dedup() {
- for category, paths := range s {
- s[category] = android.FirstUniquePaths(paths)
- }
-}
-
// HiddenAPIInfo contains information provided by the hidden API processing.
//
// That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API
@@ -554,6 +555,20 @@ func (i *HiddenAPIInfo) mergeFromFragmentDeps(ctx android.ModuleContext, fragmen
}
}
+// StubFlagSubset returns a SignatureCsvSubset that contains a path to a filtered-stub-flags.csv
+// file and a path to a signature-patterns.csv file that defines a subset of the monolithic stub
+// flags file, i.e. out/soong/hiddenapi/hiddenapi-stub-flags.txt, against which it will be compared.
+func (i *HiddenAPIInfo) StubFlagSubset() SignatureCsvSubset {
+ return SignatureCsvSubset{i.FilteredStubFlagsPath, i.SignaturePatternsPath}
+}
+
+// FlagSubset returns a SignatureCsvSubset that contains a path to a filtered-flags.csv file and a
+// path to a signature-patterns.csv file that defines a subset of the monolithic flags file, i.e.
+// out/soong/hiddenapi/hiddenapi-flags.csv, against which it will be compared.
+func (i *HiddenAPIInfo) FlagSubset() SignatureCsvSubset {
+ return SignatureCsvSubset{i.FilteredFlagsPath, i.SignaturePatternsPath}
+}
+
var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
// ModuleStubDexJars contains the stub dex jars provided by a single module.
@@ -776,9 +791,6 @@ func (i *HiddenAPIFlagInput) transitiveStubDexJarsByScope() StubDexJarsByModule
// HiddenAPIFlagOutput contains paths to output files from the hidden API flag generation for a
// bootclasspath_fragment module.
type HiddenAPIFlagOutput struct {
- // The path to the generated stub-flags.csv file.
- StubFlagsPath android.Path
-
// The path to the generated annotation-flags.csv file.
AnnotationFlagsPath android.Path
@@ -788,8 +800,21 @@ type HiddenAPIFlagOutput struct {
// The path to the generated index.csv file.
IndexPath android.Path
+ // The path to the generated stub-flags.csv file.
+ StubFlagsPath android.Path
+
// The path to the generated all-flags.csv file.
AllFlagsPath android.Path
+
+ // The path to the generated signature-patterns.txt file which defines the subset of the
+ // monolithic hidden API files provided in this.
+ SignaturePatternsPath android.Path
+
+ // The path to the generated filtered-stub-flags.csv file.
+ FilteredStubFlagsPath android.Path
+
+ // The path to the generated filtered-flags.csv file.
+ FilteredFlagsPath android.Path
}
// bootDexJarByModule is a map from base module name (without prebuilt_ prefix) to the boot dex
@@ -856,7 +881,7 @@ func pathForValidation(ctx android.PathContext, path android.WritablePath) andro
// the annotationFlags.
func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc string,
outputPath android.WritablePath, baseFlagsPath android.Path, annotationFlagPaths android.Paths,
- flagFilesByCategory FlagFilesByCategory, allFlagsPaths android.Paths, generatedRemovedDexSignatures android.OptionalPath) {
+ flagFilesByCategory FlagFilesByCategory, flagSubsets SignatureCsvSubsets, generatedRemovedDexSignatures android.OptionalPath) {
// Create the rule that will generate the flag files.
tempPath := tempPathForRestat(ctx, outputPath)
@@ -885,8 +910,9 @@ func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc st
// If there are flag files that have been generated by fragments on which this depends then use
// them to validate the flag file generated by the rules created by this method.
- if len(allFlagsPaths) > 0 {
- validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, allFlagsPaths)
+ if len(flagSubsets) > 0 {
+ validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, flagSubsets,
+ HIDDENAPI_FLAGS_CSV_IMPL_FLAGS)
// Add the file that indicates that the file generated by this is valid.
//
@@ -898,20 +924,122 @@ func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc st
rule.Build(name, desc)
}
+// SignatureCsvSubset describes a subset of a monolithic flags file, i.e. either
+// out/soong/hiddenapi/hiddenapi-stub-flags.txt or out/soong/hiddenapi/hiddenapi-flags.csv
+type SignatureCsvSubset struct {
+ // The path to the CSV file containing hidden API flags.
+ //
+ // It has the dex member signature as the first column, with flags, one per column, in the
+ // subsequent columns.
+ CsvFile android.Path
+
+ // The path to the CSV file containing the signature patterns.
+ //
+ // It is a single column CSV file with the column containing a signature pattern.
+ SignaturePatternsFile android.Path
+}
+
+type SignatureCsvSubsets []SignatureCsvSubset
+
+func (s SignatureCsvSubsets) RelativeToTop() []string {
+ result := []string{}
+ for _, subset := range s {
+ result = append(result, fmt.Sprintf("%s:%s", subset.CsvFile.RelativeToTop(), subset.SignaturePatternsFile.RelativeToTop()))
+ }
+ return result
+}
+
+// buildRuleSignaturePatternsFile creates a rule to generate a file containing the set of signature
+// patterns that will select a subset of the monolithic flags.
+func buildRuleSignaturePatternsFile(
+ ctx android.ModuleContext, flagsPath android.Path,
+ splitPackages []string, packagePrefixes []string, singlePackages []string) android.Path {
+ patternsFile := android.PathForModuleOut(ctx, "modular-hiddenapi", "signature-patterns.csv")
+ // Create a rule to validate the output from the following rule.
+ rule := android.NewRuleBuilder(pctx, ctx)
+
+ // Quote any * in the packages to avoid them being expanded by the shell.
+ quotedSplitPackages := []string{}
+ for _, pkg := range splitPackages {
+ quotedSplitPackages = append(quotedSplitPackages, strings.ReplaceAll(pkg, "*", "\\*"))
+ }
+
+ rule.Command().
+ BuiltTool("signature_patterns").
+ FlagWithInput("--flags ", flagsPath).
+ FlagForEachArg("--split-package ", quotedSplitPackages).
+ FlagForEachArg("--package-prefix ", packagePrefixes).
+ FlagForEachArg("--single-package ", singlePackages).
+ FlagWithOutput("--output ", patternsFile)
+ rule.Build("hiddenAPISignaturePatterns", "hidden API signature patterns")
+
+ return patternsFile
+}
+
+// buildRuleRemoveSignaturesWithImplementationFlags creates a rule that will remove signatures from
+// the input flags file which have only the implementation flags, i.e. are not part of an API.
+//
+// The implementationFlags specifies the set of default flags that identifies the signature of a
+// private, implementation only, member. Signatures that match those flags are removed from the
+// flags as they are implementation only.
+//
+// This is used to remove implementation only signatures from the signature files that are persisted
+// in the sdk snapshot as the sdk snapshots should not include implementation details. The
+// signatures generated by this method will be compared by the buildRuleValidateOverlappingCsvFiles
+// method which treats any missing signatures as if they were implementation only signatures.
+func buildRuleRemoveSignaturesWithImplementationFlags(ctx android.BuilderContext,
+ name string, desc string, inputPath android.Path, filteredPath android.WritablePath,
+ implementationFlags []string) {
+
+ rule := android.NewRuleBuilder(pctx, ctx)
+ implementationFlagPattern := ""
+ for _, implementationFlag := range implementationFlags {
+ implementationFlagPattern = implementationFlagPattern + "," + implementationFlag
+ }
+ rule.Command().
+ Text(`grep -vE "^[^,]+` + implementationFlagPattern + `$"`).Input(inputPath).
+ Text(">").Output(filteredPath).
+ // Grep's exit code depends on whether it finds anything. It is 0 (build success) when it finds
+ // something and 1 (build failure) when it does not and 2 (when it encounters an error).
+ // However, while it is unlikely it is not an error if this does not find any matches. The
+ // following will only run if the grep does not find something and in that case it will treat
+ // an exit code of 1 as success and anything else as failure.
+ Text("|| test $? -eq 1")
+ rule.Build(name, desc)
+}
+
// buildRuleValidateOverlappingCsvFiles checks that the modular CSV files, i.e. the files generated
// by the individual bootclasspath_fragment modules are subsets of the monolithic CSV file.
-func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name string, desc string, monolithicFilePath android.WritablePath, modularFilePaths android.Paths) android.WritablePath {
+//
+// The implementationFlags specifies the set of default flags that identifies the signature of a
+// private, implementation only, member. A signature which is present in a monolithic flags subset
+// defined by SignatureCsvSubset but which is not present in the flags file from the corresponding
+// module is assumed to be an implementation only member and so must have these flags.
+func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name string, desc string,
+ monolithicFilePath android.WritablePath, csvSubsets SignatureCsvSubsets,
+ implementationFlags []string) android.WritablePath {
// The file which is used to record that the flags file is valid.
validFile := pathForValidation(ctx, monolithicFilePath)
// Create a rule to validate the output from the following rule.
rule := android.NewRuleBuilder(pctx, ctx)
- rule.Command().
+ command := rule.Command().
BuiltTool("verify_overlaps").
- Input(monolithicFilePath).
- Inputs(modularFilePaths).
- // If validation passes then update the file that records that.
- Text("&& touch").Output(validFile)
+ FlagWithInput("--monolithic-flags ", monolithicFilePath)
+
+ for _, subset := range csvSubsets {
+ command.
+ Flag("--module-flags ").
+ Textf("%s:%s", subset.CsvFile, subset.SignaturePatternsFile).
+ Implicit(subset.CsvFile).Implicit(subset.SignaturePatternsFile)
+ }
+
+ for _, implementationFlag := range implementationFlags {
+ command.FlagWithArg("--implementation-flag ", implementationFlag)
+ }
+
+ // If validation passes then update the file that records that.
+ command.Text("&& touch").Output(validFile)
rule.Build(name+"Validation", desc+" validation")
return validFile
@@ -976,18 +1104,34 @@ func hiddenAPIRulesForBootclasspathFragment(ctx android.ModuleContext, contents
for _, name := range android.SortedStringKeys(bootDexInfoByModule) {
bootDexInfo := bootDexInfoByModule[name]
unencodedDex := bootDexInfo.path
- encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, allFlagsCSV, bootDexInfo.uncompressDex, outputDir)
+ encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, allFlagsCSV, bootDexInfo.uncompressDex, bootDexInfo.minSdkVersion, outputDir)
encodedBootDexJarsByModule[name] = encodedDex
}
+ // Generate the filtered-stub-flags.csv file which contains the filtered stub flags that will be
+ // compared against the monolithic stub flags.
+ filteredStubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-stub-flags.csv")
+ buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredStubFlags",
+ "modular hiddenapi filtered stub flags", stubFlagsCSV, filteredStubFlagsCSV,
+ HIDDENAPI_STUB_FLAGS_IMPL_FLAGS)
+
+ // Generate the filtered-flags.csv file which contains the filtered flags that will be compared
+ // against the monolithic flags.
+ filteredFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-flags.csv")
+ buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredFlags",
+ "modular hiddenapi filtered flags", allFlagsCSV, filteredFlagsCSV,
+ HIDDENAPI_FLAGS_CSV_IMPL_FLAGS)
+
// Store the paths in the info for use by other modules and sdk snapshot generation.
output := HiddenAPIOutput{
HiddenAPIFlagOutput: HiddenAPIFlagOutput{
- StubFlagsPath: stubFlagsCSV,
- AnnotationFlagsPath: annotationFlagsCSV,
- MetadataPath: metadataCSV,
- IndexPath: indexCSV,
- AllFlagsPath: allFlagsCSV,
+ AnnotationFlagsPath: annotationFlagsCSV,
+ MetadataPath: metadataCSV,
+ IndexPath: indexCSV,
+ StubFlagsPath: stubFlagsCSV,
+ AllFlagsPath: allFlagsCSV,
+ FilteredStubFlagsPath: filteredStubFlagsCSV,
+ FilteredFlagsPath: filteredFlagsCSV,
},
EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
}
@@ -1044,6 +1188,9 @@ type bootDexInfo struct {
// Indicates whether the dex jar needs uncompressing before encoding.
uncompressDex bool
+
+ // The minimum sdk version that the dex jar will be used on.
+ minSdkVersion android.SdkSpec
}
// bootDexInfoByModule is a map from module name (as returned by module.Name()) to the boot dex
@@ -1069,6 +1216,7 @@ func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android
bootDexJarsByModule[module.Name()] = bootDexInfo{
path: bootDexJar,
uncompressDex: *hiddenAPIModule.uncompressDex(),
+ minSdkVersion: hiddenAPIModule.MinSdkVersion(ctx),
}
}
@@ -1077,18 +1225,17 @@ func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android
// retrieveBootDexJarFromHiddenAPIModule retrieves the boot dex jar from the hiddenAPIModule.
//
-// If the module does not provide a boot dex jar, i.e. the returned boot dex jar is nil, then that
-// create a fake path and either report an error immediately or defer reporting of the error until
-// the path is actually used.
+// If the module does not provide a boot dex jar, i.e. the returned boot dex jar is unset or
+// invalid, then create a fake path and either report an error immediately or defer reporting of the
+// error until the path is actually used.
func retrieveBootDexJarFromHiddenAPIModule(ctx android.ModuleContext, module hiddenAPIModule) android.Path {
bootDexJar := module.bootDexJar()
- if bootDexJar == nil {
+ if !bootDexJar.Valid() {
fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/boot-dex/%s.jar", module.Name()))
- bootDexJar = fake
-
- handleMissingDexBootFile(ctx, module, fake)
+ handleMissingDexBootFile(ctx, module, fake, bootDexJar.InvalidReason())
+ return fake
}
- return bootDexJar
+ return bootDexJar.Path()
}
// extractClassesJarsFromModules extracts the class jars from the supplied modules.
@@ -1112,13 +1259,6 @@ func retrieveClassesJarsFromModule(module android.Module) android.Paths {
// deferReportingMissingBootDexJar returns true if a missing boot dex jar should not be reported by
// Soong but should instead only be reported in ninja if the file is actually built.
func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.Module) bool {
- // TODO(b/179354495): Remove this workaround when it is unnecessary.
- // Prebuilt modules like framework-wifi do not yet provide dex implementation jars. So,
- // create a fake one that will cause a build error only if it is used.
- if ctx.Config().AlwaysUsePrebuiltSdks() {
- return true
- }
-
// Any missing dependency should be allowed.
if ctx.Config().AllowMissingDependencies() {
return true
@@ -1189,7 +1329,7 @@ func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.M
// handleMissingDexBootFile will either log a warning or create an error rule to create the fake
// file depending on the value returned from deferReportingMissingBootDexJar.
-func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath) {
+func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath, reason string) {
if deferReportingMissingBootDexJar(ctx, module) {
// Create an error rule that pretends to create the output file but will actually fail if it
// is run.
@@ -1197,11 +1337,11 @@ func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module,
Rule: android.ErrorRule,
Output: fake,
Args: map[string]string{
- "error": fmt.Sprintf("missing dependencies: boot dex jar for %s", module),
+ "error": fmt.Sprintf("missing boot dex jar dependency for %s: %s", module, reason),
},
})
} else {
- ctx.ModuleErrorf("module %s does not provide a dex jar", module)
+ ctx.ModuleErrorf("module %s does not provide a dex jar: %s", module, reason)
}
}
@@ -1212,14 +1352,13 @@ func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module,
// However, under certain conditions, e.g. errors, or special build configurations it will return
// a path to a fake file.
func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.Module) android.Path {
- bootDexJar := module.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath()
- if bootDexJar == nil {
+ bootDexJar := module.(interface{ DexJarBuildPath() OptionalDexJarPath }).DexJarBuildPath()
+ if !bootDexJar.Valid() {
fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/encoded-dex/%s.jar", module.Name()))
- bootDexJar = fake
-
- handleMissingDexBootFile(ctx, module, fake)
+ handleMissingDexBootFile(ctx, module, fake, bootDexJar.InvalidReason())
+ return fake
}
- return bootDexJar
+ return bootDexJar.Path()
}
// extractEncodedDexJarsFromModules extracts the encoded dex jars from the supplied modules.
diff --git a/java/hiddenapi_monolithic.go b/java/hiddenapi_monolithic.go
index 52f0770f3..5956e3c6c 100644
--- a/java/hiddenapi_monolithic.go
+++ b/java/hiddenapi_monolithic.go
@@ -29,9 +29,6 @@ type MonolithicHiddenAPIInfo struct {
// that category.
FlagsFilesByCategory FlagFilesByCategory
- // The paths to the generated stub-flags.csv files.
- StubFlagsPaths android.Paths
-
// The paths to the generated annotation-flags.csv files.
AnnotationFlagsPaths android.Paths
@@ -41,8 +38,13 @@ type MonolithicHiddenAPIInfo struct {
// The paths to the generated index.csv files.
IndexPaths android.Paths
- // The paths to the generated all-flags.csv files.
- AllFlagsPaths android.Paths
+ // The subsets of the monolithic hiddenapi-stubs-flags.txt file that are provided by each
+ // bootclasspath_fragment modules.
+ StubFlagSubsets SignatureCsvSubsets
+
+ // The subsets of the monolithic hiddenapi-flags.csv file that are provided by each
+ // bootclasspath_fragment modules.
+ FlagSubsets SignatureCsvSubsets
// The classes jars from the libraries on the platform bootclasspath.
ClassesJars android.Paths
@@ -58,68 +60,34 @@ func newMonolithicHiddenAPIInfo(ctx android.ModuleContext, flagFilesByCategory F
// Merge all the information from the classpathElements. The fragments form a DAG so it is possible that
// this will introduce duplicates so they will be resolved after processing all the classpathElements.
for _, element := range classpathElements {
- var classesJars android.Paths
switch e := element.(type) {
case *ClasspathLibraryElement:
- classesJars = retrieveClassesJarsFromModule(e.Module())
+ classesJars := retrieveClassesJarsFromModule(e.Module())
+ monolithicInfo.ClassesJars = append(monolithicInfo.ClassesJars, classesJars...)
case *ClasspathFragmentElement:
fragment := e.Module()
if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
monolithicInfo.append(&info)
-
- // If the bootclasspath fragment actually perform hidden API processing itself then use the
- // CSV files it provides and do not bother processing the classesJars files. This ensures
- // consistent behavior between source and prebuilt as prebuilt modules do not provide
- // classesJars.
- if info.AllFlagsPath != nil {
- continue
- }
+ } else {
+ ctx.ModuleErrorf("%s does not provide hidden API information", fragment)
}
-
- classesJars = extractClassesJarsFromModules(e.Contents)
}
-
- monolithicInfo.ClassesJars = append(monolithicInfo.ClassesJars, classesJars...)
}
- // Dedup paths.
- monolithicInfo.dedup()
-
return monolithicInfo
}
// append appends all the files from the supplied info to the corresponding files in this struct.
func (i *MonolithicHiddenAPIInfo) append(other *HiddenAPIInfo) {
i.FlagsFilesByCategory.append(other.FlagFilesByCategory)
+ i.AnnotationFlagsPaths = append(i.AnnotationFlagsPaths, other.AnnotationFlagsPath)
+ i.MetadataPaths = append(i.MetadataPaths, other.MetadataPath)
+ i.IndexPaths = append(i.IndexPaths, other.IndexPath)
- // The output may not be set if the bootclasspath_fragment has not yet been updated to support
- // hidden API processing.
- // TODO(b/179354495): Switch back to append once all bootclasspath_fragment modules have been
- // updated to support hidden API processing properly.
- appendIfNotNil := func(paths android.Paths, path android.Path) android.Paths {
- if path == nil {
- return paths
- }
- return append(paths, path)
- }
- i.StubFlagsPaths = appendIfNotNil(i.StubFlagsPaths, other.StubFlagsPath)
- i.AnnotationFlagsPaths = appendIfNotNil(i.AnnotationFlagsPaths, other.AnnotationFlagsPath)
- i.MetadataPaths = appendIfNotNil(i.MetadataPaths, other.MetadataPath)
- i.IndexPaths = appendIfNotNil(i.IndexPaths, other.IndexPath)
- i.AllFlagsPaths = appendIfNotNil(i.AllFlagsPaths, other.AllFlagsPath)
-}
-
-// dedup removes duplicates in all the paths, while maintaining the order in which they were
-// appended.
-func (i *MonolithicHiddenAPIInfo) dedup() {
- i.FlagsFilesByCategory.dedup()
- i.StubFlagsPaths = android.FirstUniquePaths(i.StubFlagsPaths)
- i.AnnotationFlagsPaths = android.FirstUniquePaths(i.AnnotationFlagsPaths)
- i.MetadataPaths = android.FirstUniquePaths(i.MetadataPaths)
- i.IndexPaths = android.FirstUniquePaths(i.IndexPaths)
- i.AllFlagsPaths = android.FirstUniquePaths(i.AllFlagsPaths)
+ i.StubFlagSubsets = append(i.StubFlagSubsets, other.StubFlagSubset())
+ i.FlagSubsets = append(i.FlagSubsets, other.FlagSubset())
}
var MonolithicHiddenAPIInfoProvider = blueprint.NewProvider(MonolithicHiddenAPIInfo{})
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
index dcd363c2c..75b7bb7c8 100644
--- a/java/hiddenapi_singleton_test.go
+++ b/java/hiddenapi_singleton_test.go
@@ -20,6 +20,7 @@ import (
"testing"
"android/soong/android"
+
"github.com/google/blueprint/proptools"
)
@@ -306,7 +307,7 @@ func TestHiddenAPIEncoding_JavaSdkLibrary(t *testing.T) {
android.AssertStringEquals(t, "encode embedded java_library", unencodedDexJar, actualUnencodedDexJar.String())
// Make sure that the encoded dex jar is the exported one.
- exportedDexJar := moduleForTests.Module().(UsesLibraryDependency).DexJarBuildPath()
+ exportedDexJar := moduleForTests.Module().(UsesLibraryDependency).DexJarBuildPath().Path()
android.AssertPathRelativeToTopEquals(t, "encode embedded java_library", encodedDexJar, exportedDexJar)
}
diff --git a/java/jacoco.go b/java/jacoco.go
index 9162161d3..e11c2ce69 100644
--- a/java/jacoco.go
+++ b/java/jacoco.go
@@ -94,7 +94,7 @@ func jacocoFiltersToZipCommand(includes, excludes []string) string {
if len(includes) > 0 {
specs += strings.Join(includes, " ")
} else {
- specs += "**/*.class"
+ specs += "'**/*.class'"
}
return specs
}
diff --git a/java/jacoco_test.go b/java/jacoco_test.go
index 91f05535a..1882908ca 100644
--- a/java/jacoco_test.go
+++ b/java/jacoco_test.go
@@ -74,7 +74,7 @@ func TestJacocoFiltersToZipCommand(t *testing.T) {
{
name: "implicit wildcard",
includes: []string{},
- out: "**/*.class",
+ out: "'**/*.class'",
},
{
name: "only include",
diff --git a/java/java.go b/java/java.go
index bbed42def..c8fb93cca 100644
--- a/java/java.go
+++ b/java/java.go
@@ -23,6 +23,8 @@ import (
"path/filepath"
"strings"
+ "android/soong/bazel"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -74,6 +76,7 @@ func RegisterJavaSdkMemberTypes() {
android.RegisterSdkMemberType(javaHeaderLibsSdkMemberType)
android.RegisterSdkMemberType(javaLibsSdkMemberType)
android.RegisterSdkMemberType(javaBootLibsSdkMemberType)
+ android.RegisterSdkMemberType(javaSystemserverLibsSdkMemberType)
android.RegisterSdkMemberType(javaTestSdkMemberType)
}
@@ -131,11 +134,50 @@ var (
PropertyName: "java_boot_libs",
SupportsSdk: true,
},
- // Temporarily export implementation classes jar for java_boot_libs as it is required for the
- // hiddenapi processing.
- // TODO(b/179354495): Revert once hiddenapi processing has been modularized.
- exportImplementationClassesJar,
- sdkSnapshotFilePathForJar,
+ func(ctx android.SdkMemberContext, j *Library) android.Path {
+ // Java boot libs are only provided in the SDK to provide access to their dex implementation
+ // jar for use by dexpreopting and boot jars package check. They do not need to provide an
+ // actual implementation jar but the java_import will need a file that exists so just copy an
+ // empty file. Any attempt to use that file as a jar will cause a build error.
+ return ctx.SnapshotBuilder().EmptyFile()
+ },
+ func(osPrefix, name string) string {
+ // Create a special name for the implementation jar to try and provide some useful information
+ // to a developer that attempts to compile against this.
+ // TODO(b/175714559): Provide a proper error message in Soong not ninja.
+ return filepath.Join(osPrefix, "java_boot_libs", "snapshot", "jars", "are", "invalid", name+jarFileSuffix)
+ },
+ onlyCopyJarToSnapshot,
+ }
+
+ // Supports adding java systemserver libraries to module_exports and sdk.
+ //
+ // The build has some implicit dependencies (via the systemserver jars configuration) on a number
+ // of modules that are part of the java systemserver classpath and which are provided by mainline
+ // modules but which are not otherwise used outside those mainline modules.
+ //
+ // As they are not needed outside the mainline modules adding them to the sdk/module-exports as
+ // either java_libs, or java_header_libs would end up exporting more information than was strictly
+ // necessary. The java_systemserver_libs property to allow those modules to be exported as part of
+ // the sdk/module_exports without exposing any unnecessary information.
+ javaSystemserverLibsSdkMemberType = &librarySdkMemberType{
+ android.SdkMemberTypeBase{
+ PropertyName: "java_systemserver_libs",
+ SupportsSdk: true,
+ },
+ func(ctx android.SdkMemberContext, j *Library) android.Path {
+ // Java systemserver libs are only provided in the SDK to provide access to their dex
+ // implementation jar for use by dexpreopting. They do not need to provide an actual
+ // implementation jar but the java_import will need a file that exists so just copy an empty
+ // file. Any attempt to use that file as a jar will cause a build error.
+ return ctx.SnapshotBuilder().EmptyFile()
+ },
+ func(osPrefix, name string) string {
+ // Create a special name for the implementation jar to try and provide some useful information
+ // to a developer that attempts to compile against this.
+ // TODO(b/175714559): Provide a proper error message in Soong not ninja.
+ return filepath.Join(osPrefix, "java_systemserver_libs", "snapshot", "jars", "are", "invalid", name+jarFileSuffix)
+ },
onlyCopyJarToSnapshot,
}
@@ -212,7 +254,7 @@ type ApexDependency interface {
// Provides build path and install path to DEX jars.
type UsesLibraryDependency interface {
- DexJarBuildPath() android.Path
+ DexJarBuildPath() OptionalDexJarPath
DexJarInstallPath() android.Path
ClassLoaderContexts() dexpreopt.ClassLoaderContextMap
}
@@ -229,6 +271,12 @@ func (j *Module) XrefJavaFiles() android.Paths {
type dependencyTag struct {
blueprint.BaseDependencyTag
name string
+
+ // True if the dependency is relinked at runtime.
+ runtimeLinked bool
+
+ // True if the dependency is a toolchain, for example an annotation processor.
+ toolchain bool
}
// installDependencyTag is a dependency tag that is annotated to cause the installed files of the
@@ -239,15 +287,40 @@ type installDependencyTag struct {
name string
}
+func (d dependencyTag) LicenseAnnotations() []android.LicenseAnnotation {
+ if d.runtimeLinked {
+ return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency}
+ } else if d.toolchain {
+ return []android.LicenseAnnotation{android.LicenseAnnotationToolchain}
+ }
+ return nil
+}
+
+var _ android.LicenseAnnotationsDependencyTag = dependencyTag{}
+
type usesLibraryDependencyTag struct {
dependencyTag
- sdkVersion int // SDK version in which the library appared as a standalone library.
+
+ // SDK version in which the library appared as a standalone library.
+ sdkVersion int
+
+ // If the dependency is optional or required.
+ optional bool
+
+ // Whether this is an implicit dependency inferred by Soong, or an explicit one added via
+ // `uses_libs`/`optional_uses_libs` properties.
+ implicit bool
}
-func makeUsesLibraryDependencyTag(sdkVersion int) usesLibraryDependencyTag {
+func makeUsesLibraryDependencyTag(sdkVersion int, optional bool, implicit bool) usesLibraryDependencyTag {
return usesLibraryDependencyTag{
- dependencyTag: dependencyTag{name: fmt.Sprintf("uses-library-%d", sdkVersion)},
- sdkVersion: sdkVersion,
+ dependencyTag: dependencyTag{
+ name: fmt.Sprintf("uses-library-%d", sdkVersion),
+ runtimeLinked: true,
+ },
+ sdkVersion: sdkVersion,
+ optional: optional,
+ implicit: implicit,
}
}
@@ -257,29 +330,27 @@ func IsJniDepTag(depTag blueprint.DependencyTag) bool {
var (
dataNativeBinsTag = dependencyTag{name: "dataNativeBins"}
+ dataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"}
staticLibTag = dependencyTag{name: "staticlib"}
- libTag = dependencyTag{name: "javalib"}
- java9LibTag = dependencyTag{name: "java9lib"}
- pluginTag = dependencyTag{name: "plugin"}
- errorpronePluginTag = dependencyTag{name: "errorprone-plugin"}
- exportedPluginTag = dependencyTag{name: "exported-plugin"}
- bootClasspathTag = dependencyTag{name: "bootclasspath"}
- systemModulesTag = dependencyTag{name: "system modules"}
+ libTag = dependencyTag{name: "javalib", runtimeLinked: true}
+ java9LibTag = dependencyTag{name: "java9lib", runtimeLinked: true}
+ pluginTag = dependencyTag{name: "plugin", toolchain: true}
+ errorpronePluginTag = dependencyTag{name: "errorprone-plugin", toolchain: true}
+ exportedPluginTag = dependencyTag{name: "exported-plugin", toolchain: true}
+ bootClasspathTag = dependencyTag{name: "bootclasspath", runtimeLinked: true}
+ systemModulesTag = dependencyTag{name: "system modules", runtimeLinked: true}
frameworkResTag = dependencyTag{name: "framework-res"}
- kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib"}
- kotlinAnnotationsTag = dependencyTag{name: "kotlin-annotations"}
+ kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib", runtimeLinked: true}
+ kotlinAnnotationsTag = dependencyTag{name: "kotlin-annotations", runtimeLinked: true}
+ kotlinPluginTag = dependencyTag{name: "kotlin-plugin", toolchain: true}
proguardRaiseTag = dependencyTag{name: "proguard-raise"}
certificateTag = dependencyTag{name: "certificate"}
instrumentationForTag = dependencyTag{name: "instrumentation_for"}
- extraLintCheckTag = dependencyTag{name: "extra-lint-check"}
- jniLibTag = dependencyTag{name: "jnilib"}
+ extraLintCheckTag = dependencyTag{name: "extra-lint-check", toolchain: true}
+ jniLibTag = dependencyTag{name: "jnilib", runtimeLinked: true}
syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"}
jniInstallTag = installDependencyTag{name: "jni install"}
binaryInstallTag = installDependencyTag{name: "binary install"}
- usesLibTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion)
- usesLibCompat28Tag = makeUsesLibraryDependencyTag(28)
- usesLibCompat29Tag = makeUsesLibraryDependencyTag(29)
- usesLibCompat30Tag = makeUsesLibraryDependencyTag(30)
)
func IsLibDepTag(depTag blueprint.DependencyTag) bool {
@@ -350,9 +421,25 @@ func sdkDeps(ctx android.BottomUpMutatorContext, sdkContext android.SdkContext,
}
type deps struct {
- classpath classpath
- java9Classpath classpath
- bootClasspath classpath
+ // bootClasspath is the list of jars that form the boot classpath (generally the java.* and
+ // android.* classes) for tools that still use it. javac targeting 1.9 or higher uses
+ // systemModules and java9Classpath instead.
+ bootClasspath classpath
+
+ // classpath is the list of jars that form the classpath for javac and kotlinc rules. It
+ // contains header jars for all static and non-static dependencies.
+ classpath classpath
+
+ // dexClasspath is the list of jars that form the classpath for d8 and r8 rules. It contains
+ // header jars for all non-static dependencies. Static dependencies have already been
+ // combined into the program jar.
+ dexClasspath classpath
+
+ // java9Classpath is the list of jars that will be added to the classpath when targeting
+ // 1.9 or higher. It generally contains the android.* classes, while the java.* classes
+ // are provided by systemModules.
+ java9Classpath classpath
+
processorPath classpath
errorProneProcessorPath classpath
processorClasses []string
@@ -366,6 +453,7 @@ type deps struct {
aidlPreprocess android.OptionalPath
kotlinStdlib android.Paths
kotlinAnnotations android.Paths
+ kotlinPlugins android.Paths
disableTurbine bool
}
@@ -385,7 +473,7 @@ func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext an
} else if ctx.Device() {
return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion(ctx))
} else {
- return JAVA_VERSION_9
+ return JAVA_VERSION_11
}
}
@@ -397,6 +485,7 @@ const (
JAVA_VERSION_7 = 7
JAVA_VERSION_8 = 8
JAVA_VERSION_9 = 9
+ JAVA_VERSION_11 = 11
)
func (v javaVersion) String() string {
@@ -409,6 +498,8 @@ func (v javaVersion) String() string {
return "1.8"
case JAVA_VERSION_9:
return "1.9"
+ case JAVA_VERSION_11:
+ return "11"
default:
return "unsupported"
}
@@ -429,8 +520,10 @@ func normalizeJavaVersion(ctx android.BaseModuleContext, javaVersion string) jav
return JAVA_VERSION_8
case "1.9", "9":
return JAVA_VERSION_9
- case "10", "11":
- ctx.PropertyErrorf("java_version", "Java language levels above 9 are not supported")
+ case "11":
+ return JAVA_VERSION_11
+ case "10":
+ ctx.PropertyErrorf("java_version", "Java language levels 10 is not supported")
return JAVA_VERSION_UNSUPPORTED
default:
ctx.PropertyErrorf("java_version", "Unrecognized Java language level")
@@ -450,7 +543,7 @@ type Library struct {
var _ android.ApexModule = (*Library)(nil)
-// Provides access to the list of permitted packages from updatable boot jars.
+// Provides access to the list of permitted packages from apex boot jars.
type PermittedPackagesForUpdatableBootJars interface {
PermittedPackagesForUpdatableBootJars() []string
}
@@ -473,7 +566,7 @@ func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bo
}
// Store uncompressed dex files that are preopted on /system.
- if !dexpreopter.dexpreoptDisabled(ctx) && (ctx.Host() || !odexOnSystemOther(ctx, dexpreopter.installPath)) {
+ if !dexpreopter.dexpreoptDisabled(ctx) && (ctx.Host() || !dexpreopter.odexOnSystemOther(ctx, dexpreopter.installPath)) {
return true
}
if ctx.Config().UncompressPrivAppDex() &&
@@ -484,9 +577,18 @@ func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bo
return false
}
+// Sets `dexer.dexProperties.Uncompress_dex` to the proper value.
+func setUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter, dexer *dexer) {
+ if dexer.dexProperties.Uncompress_dex == nil {
+ // If the value was not force-set by the user, use reasonable default based on the module.
+ dexer.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, dexpreopter))
+ }
+}
+
func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.sdkVersion = j.SdkVersion(ctx)
j.minSdkVersion = j.MinSdkVersion(ctx)
+ j.maxSdkVersion = j.MaxSdkVersion(ctx)
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if !apexInfo.IsForPlatform() {
@@ -494,14 +596,12 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
j.checkSdkVersions(ctx)
- j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
+ j.dexpreopter.installPath = j.dexpreopter.getInstallPath(
+ ctx, android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar"))
j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
- if j.dexProperties.Uncompress_dex == nil {
- // If the value was not force-set by the user, use reasonable default based on the module.
- j.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter))
- }
+ setUncompressDex(ctx, &j.dexpreopter, &j.dexer)
j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
- j.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap)
+ j.classLoaderContexts = j.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
j.compile(ctx, nil)
// Collect the module directory for IDE info in java/jdeps.go.
@@ -513,13 +613,29 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if j.InstallMixin != nil {
extraInstallDeps = j.InstallMixin(ctx, j.outputFile)
}
- j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
- j.Stem()+".jar", j.outputFile, extraInstallDeps...)
+ hostDexNeeded := Bool(j.deviceProperties.Hostdex) && !ctx.Host()
+ if hostDexNeeded {
+ j.hostdexInstallFile = ctx.InstallFile(
+ android.PathForHostDexInstall(ctx, "framework"),
+ j.Stem()+"-hostdex.jar", j.outputFile)
+ }
+ var installDir android.InstallPath
+ if ctx.InstallInTestcases() {
+ var archDir string
+ if !ctx.Host() {
+ archDir = ctx.DeviceConfig().DeviceArch()
+ }
+ installDir = android.PathForModuleInstall(ctx, ctx.ModuleName(), archDir)
+ } else {
+ installDir = android.PathForModuleInstall(ctx, "framework")
+ }
+ j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...)
}
}
func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
j.deps(ctx)
+ j.usesLibrary.deps(ctx, false)
}
const (
@@ -559,8 +675,8 @@ const (
copyEverythingToSnapshot = false
)
-func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
- mctx.AddVariationDependencies(nil, dependencyTag, names...)
+func (mt *librarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ ctx.AddVariationDependencies(nil, dependencyTag, names...)
}
func (mt *librarySdkMemberType) IsInstance(module android.Module) bool {
@@ -657,6 +773,7 @@ func LibraryFactory() android.Module {
android.InitApexModule(module)
android.InitSdkAwareModule(module)
+ android.InitBazelModule(module)
InitJavaModule(module, android.HostAndDeviceSupported)
return module
}
@@ -679,6 +796,7 @@ func LibraryHostFactory() android.Module {
android.InitApexModule(module)
android.InitSdkAwareModule(module)
+ android.InitBazelModule(module)
InitJavaModule(module, android.HostSupported)
return module
}
@@ -727,17 +845,44 @@ type testProperties struct {
// Names of modules containing JNI libraries that should be installed alongside the test.
Jni_libs []string
+
+ // Install the test into a folder named for the module in all test suites.
+ Per_testcase_directory *bool
}
type hostTestProperties struct {
// list of native binary modules that should be installed alongside the test
Data_native_bins []string `android:"arch_variant"`
+
+ // list of device binary modules that should be installed alongside the test
+ // This property only adds the first variant of the dependency
+ Data_device_bins_first []string `android:"arch_variant"`
+
+ // list of device binary modules that should be installed alongside the test
+ // This property adds 64bit AND 32bit variants of the dependency
+ Data_device_bins_both []string `android:"arch_variant"`
+
+ // list of device binary modules that should be installed alongside the test
+ // This property only adds 64bit variants of the dependency
+ Data_device_bins_64 []string `android:"arch_variant"`
+
+ // list of device binary modules that should be installed alongside the test
+ // This property adds 32bit variants of the dependency if available, or else
+ // defaults to the 64bit variant
+ Data_device_bins_prefer32 []string `android:"arch_variant"`
+
+ // list of device binary modules that should be installed alongside the test
+ // This property only adds 32bit variants of the dependency
+ Data_device_bins_32 []string `android:"arch_variant"`
}
type testHelperLibraryProperties struct {
// list of compatibility suites (for example "cts", "vts") that the module should be
// installed into.
Test_suites []string `android:"arch_variant"`
+
+ // Install the test into a folder named for the module in all test suites.
+ Per_testcase_directory *bool
}
type prebuiltTestProperties struct {
@@ -781,6 +926,97 @@ type JavaTestImport struct {
dexJarFile android.Path
}
+func (j *Test) InstallInTestcases() bool {
+ // Host java tests install into $(HOST_OUT_JAVA_LIBRARIES), and then are copied into
+ // testcases by base_rules.mk.
+ return !j.Host()
+}
+
+func (j *TestHelperLibrary) InstallInTestcases() bool {
+ return true
+}
+
+func (j *JavaTestImport) InstallInTestcases() bool {
+ return true
+}
+
+func (j *TestHost) addDataDeviceBinsDeps(ctx android.BottomUpMutatorContext) {
+ if len(j.testHostProperties.Data_device_bins_first) > 0 {
+ deviceVariations := ctx.Config().AndroidFirstDeviceTarget.Variations()
+ ctx.AddFarVariationDependencies(deviceVariations, dataDeviceBinsTag, j.testHostProperties.Data_device_bins_first...)
+ }
+
+ var maybeAndroid32Target *android.Target
+ var maybeAndroid64Target *android.Target
+ android32TargetList := android.FirstTarget(ctx.Config().Targets[android.Android], "lib32")
+ android64TargetList := android.FirstTarget(ctx.Config().Targets[android.Android], "lib64")
+ if len(android32TargetList) > 0 {
+ maybeAndroid32Target = &android32TargetList[0]
+ }
+ if len(android64TargetList) > 0 {
+ maybeAndroid64Target = &android64TargetList[0]
+ }
+
+ if len(j.testHostProperties.Data_device_bins_both) > 0 {
+ if maybeAndroid32Target == nil && maybeAndroid64Target == nil {
+ ctx.PropertyErrorf("data_device_bins_both", "no device targets available. Targets: %q", ctx.Config().Targets)
+ return
+ }
+ if maybeAndroid32Target != nil {
+ ctx.AddFarVariationDependencies(
+ maybeAndroid32Target.Variations(),
+ dataDeviceBinsTag,
+ j.testHostProperties.Data_device_bins_both...,
+ )
+ }
+ if maybeAndroid64Target != nil {
+ ctx.AddFarVariationDependencies(
+ maybeAndroid64Target.Variations(),
+ dataDeviceBinsTag,
+ j.testHostProperties.Data_device_bins_both...,
+ )
+ }
+ }
+
+ if len(j.testHostProperties.Data_device_bins_prefer32) > 0 {
+ if maybeAndroid32Target != nil {
+ ctx.AddFarVariationDependencies(
+ maybeAndroid32Target.Variations(),
+ dataDeviceBinsTag,
+ j.testHostProperties.Data_device_bins_prefer32...,
+ )
+ } else {
+ if maybeAndroid64Target == nil {
+ ctx.PropertyErrorf("data_device_bins_prefer32", "no device targets available. Targets: %q", ctx.Config().Targets)
+ return
+ }
+ ctx.AddFarVariationDependencies(
+ maybeAndroid64Target.Variations(),
+ dataDeviceBinsTag,
+ j.testHostProperties.Data_device_bins_prefer32...,
+ )
+ }
+ }
+
+ if len(j.testHostProperties.Data_device_bins_32) > 0 {
+ if maybeAndroid32Target == nil {
+ ctx.PropertyErrorf("data_device_bins_32", "cannot find 32bit device target. Targets: %q", ctx.Config().Targets)
+ return
+ }
+ deviceVariations := maybeAndroid32Target.Variations()
+ ctx.AddFarVariationDependencies(deviceVariations, dataDeviceBinsTag, j.testHostProperties.Data_device_bins_32...)
+ }
+
+ if len(j.testHostProperties.Data_device_bins_64) > 0 {
+ if maybeAndroid64Target == nil {
+ ctx.PropertyErrorf("data_device_bins_64", "cannot find 64bit device target. Targets: %q", ctx.Config().Targets)
+ return
+ }
+ deviceVariations := maybeAndroid64Target.Variations()
+ ctx.AddFarVariationDependencies(deviceVariations, dataDeviceBinsTag, j.testHostProperties.Data_device_bins_64...)
+ }
+}
+
func (j *TestHost) DepsMutator(ctx android.BottomUpMutatorContext) {
if len(j.testHostProperties.Data_native_bins) > 0 {
for _, target := range ctx.MultiTargets() {
@@ -795,6 +1031,8 @@ func (j *TestHost) DepsMutator(ctx android.BottomUpMutatorContext) {
}
}
+ j.addDataDeviceBinsDeps(ctx)
+
j.deps(ctx)
}
@@ -802,14 +1040,58 @@ func (j *TestHost) AddExtraResource(p android.Path) {
j.extraResources = append(j.extraResources, p)
}
+func (j *TestHost) dataDeviceBins() []string {
+ ret := make([]string, 0,
+ len(j.testHostProperties.Data_device_bins_first)+
+ len(j.testHostProperties.Data_device_bins_both)+
+ len(j.testHostProperties.Data_device_bins_prefer32)+
+ len(j.testHostProperties.Data_device_bins_32)+
+ len(j.testHostProperties.Data_device_bins_64),
+ )
+
+ ret = append(ret, j.testHostProperties.Data_device_bins_first...)
+ ret = append(ret, j.testHostProperties.Data_device_bins_both...)
+ ret = append(ret, j.testHostProperties.Data_device_bins_prefer32...)
+ ret = append(ret, j.testHostProperties.Data_device_bins_32...)
+ ret = append(ret, j.testHostProperties.Data_device_bins_64...)
+
+ return ret
+}
+
+func (j *TestHost) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ var configs []tradefed.Config
+ dataDeviceBins := j.dataDeviceBins()
+ if len(dataDeviceBins) > 0 {
+ // add Tradefed configuration to push device bins to device for testing
+ remoteDir := filepath.Join("/data/local/tests/unrestricted/", j.Name())
+ options := []tradefed.Option{{Name: "cleanup", Value: "true"}}
+ for _, bin := range dataDeviceBins {
+ fullPath := filepath.Join(remoteDir, bin)
+ options = append(options, tradefed.Option{Name: "push-file", Key: bin, Value: fullPath})
+ }
+ configs = append(configs, tradefed.Object{
+ Type: "target_preparer",
+ Class: "com.android.tradefed.targetprep.PushFilePreparer",
+ Options: options,
+ })
+ }
+
+ j.Test.generateAndroidBuildActionsWithConfig(ctx, configs)
+}
+
func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ j.generateAndroidBuildActionsWithConfig(ctx, nil)
+}
+
+func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, configs []tradefed.Config) {
if j.testProperties.Test_options.Unit_test == nil && ctx.Host() {
// TODO(b/): Clean temporary heuristic to avoid unexpected onboarding.
defaultUnitTest := !inList("tradefed", j.properties.Libs) && !inList("cts", j.testProperties.Test_suites)
j.testProperties.Test_options.Unit_test = proptools.BoolPtr(defaultUnitTest)
}
+
j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template,
- j.testProperties.Test_suites, j.testProperties.Auto_gen_config, j.testProperties.Test_options.Unit_test)
+ j.testProperties.Test_suites, configs, j.testProperties.Auto_gen_config, j.testProperties.Test_options.Unit_test)
j.data = android.PathsForModuleSrc(ctx, j.testProperties.Data)
@@ -819,6 +1101,10 @@ func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.data = append(j.data, android.OutputFileForModule(ctx, dep, ""))
})
+ ctx.VisitDirectDepsWithTag(dataDeviceBinsTag, func(dep android.Module) {
+ j.data = append(j.data, android.OutputFileForModule(ctx, dep, ""))
+ })
+
ctx.VisitDirectDepsWithTag(jniLibTag, func(dep android.Module) {
sharedLibInfo := ctx.OtherModuleProvider(dep, cc.SharedLibraryInfoProvider).(cc.SharedLibraryInfo)
if sharedLibInfo.SharedLibrary != nil {
@@ -851,7 +1137,7 @@ func (j *TestHelperLibrary) GenerateAndroidBuildActions(ctx android.ModuleContex
func (j *JavaTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.prebuiltTestProperties.Test_config, nil,
- j.prebuiltTestProperties.Test_suites, nil, nil)
+ j.prebuiltTestProperties.Test_suites, nil, nil, nil)
j.Import.GenerateAndroidBuildActions(ctx)
}
@@ -860,8 +1146,8 @@ type testSdkMemberType struct {
android.SdkMemberTypeBase
}
-func (mt *testSdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
- mctx.AddVariationDependencies(nil, dependencyTag, names...)
+func (mt *testSdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ ctx.AddVariationDependencies(nil, dependencyTag, names...)
}
func (mt *testSdkMemberType) IsInstance(module android.Module) bool {
@@ -1012,14 +1298,14 @@ func InitTestHost(th *TestHost, installable *bool, testSuites []string, autoGenC
type binaryProperties struct {
// installable script to execute the resulting jar
- Wrapper *string `android:"path"`
+ Wrapper *string `android:"path,arch_variant"`
// Name of the class containing main to be inserted into the manifest as Main-Class.
Main_class *string
// Names of modules containing JNI libraries that should be installed alongside the host
// variant of the binary.
- Jni_libs []string
+ Jni_libs []string `android:"arch_variant"`
}
type Binary struct {
@@ -1057,14 +1343,23 @@ func (j *Binary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if j.binaryProperties.Wrapper != nil {
j.wrapperFile = android.PathForModuleSrc(ctx, *j.binaryProperties.Wrapper)
} else {
+ if ctx.Windows() {
+ ctx.PropertyErrorf("wrapper", "wrapper is required for Windows")
+ }
+
j.wrapperFile = android.PathForSource(ctx, "build/soong/scripts/jar-wrapper.sh")
}
+ ext := ""
+ if ctx.Windows() {
+ ext = ".bat"
+ }
+
// The host installation rules make the installed wrapper depend on all the dependencies
// of the wrapper variant, which will include the common variant's jar file and any JNI
// libraries. This is verified by TestBinary.
j.binaryFile = ctx.InstallExecutable(android.PathForModuleInstall(ctx, "bin"),
- ctx.ModuleName(), j.wrapperFile)
+ ctx.ModuleName()+ext, j.wrapperFile)
}
}
@@ -1100,6 +1395,8 @@ func BinaryFactory() android.Module {
android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommonFirst)
android.InitDefaultableModule(module)
+ android.InitBazelModule(module)
+
return module
}
@@ -1117,6 +1414,7 @@ func BinaryHostFactory() android.Module {
android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommonFirst)
android.InitDefaultableModule(module)
+ android.InitBazelModule(module)
return module
}
@@ -1138,7 +1436,6 @@ type ImportProperties struct {
Installable *bool
// If not empty, classes are restricted to the specified packages and their sub-packages.
- // This information is used to generate the updatable-bcp-packages.txt file.
Permitted_packages []string
// List of shared java libs that this module has dependencies to
@@ -1167,6 +1464,7 @@ type Import struct {
android.ModuleBase
android.DefaultableModuleBase
android.ApexModuleBase
+ android.BazelModuleBase
prebuilt android.Prebuilt
android.SdkBase
@@ -1180,7 +1478,8 @@ type Import struct {
properties ImportProperties
// output file containing classes.dex and resources
- dexJarFile android.Path
+ dexJarFile OptionalDexJarPath
+ dexJarInstallFile android.Path
combinedClasspathFile android.Path
classLoaderContexts dexpreopt.ClassLoaderContextMap
@@ -1264,6 +1563,10 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.hideApexVariantFromMake = true
}
+ if ctx.Windows() {
+ j.HideFromMake()
+ }
+
jars := android.PathsForModuleSrc(ctx, j.properties.Jars)
jarName := j.Stem() + ".jar"
@@ -1279,7 +1582,6 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap)
var flags javaBuilderFlags
- var deapexerModule android.Module
ctx.VisitDirectDeps(func(module android.Module) {
tag := ctx.OtherModuleDependencyTag(module)
@@ -1287,7 +1589,10 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
switch tag {
- case libTag, staticLibTag:
+ case libTag:
+ flags.classpath = append(flags.classpath, dep.HeaderJars...)
+ flags.dexClasspath = append(flags.dexClasspath, dep.HeaderJars...)
+ case staticLibTag:
flags.classpath = append(flags.classpath, dep.HeaderJars...)
case bootClasspathTag:
flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars...)
@@ -1300,20 +1605,20 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
addCLCFromDep(ctx, module, j.classLoaderContexts)
-
- // Save away the `deapexer` module on which this depends, if any.
- if tag == android.DeapexerTag {
- if deapexerModule != nil {
- ctx.ModuleErrorf("Ambiguous duplicate deapexer module dependencies %q and %q",
- deapexerModule.Name(), module.Name())
- }
- deapexerModule = module
- }
})
if Bool(j.properties.Installable) {
- ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
- jarName, outputFile)
+ var installDir android.InstallPath
+ if ctx.InstallInTestcases() {
+ var archDir string
+ if !ctx.Host() {
+ archDir = ctx.DeviceConfig().DeviceArch()
+ }
+ installDir = android.PathForModuleInstall(ctx, ctx.ModuleName(), archDir)
+ } else {
+ installDir = android.PathForModuleInstall(ctx, "framework")
+ }
+ ctx.InstallFile(installDir, jarName, outputFile)
}
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
@@ -1323,25 +1628,28 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// obtained from the associated deapexer module.
ai := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if ai.ForPrebuiltApex {
- if deapexerModule == nil {
- // This should never happen as a variant for a prebuilt_apex is only created if the
- // deapexer module has been configured to export the dex implementation jar for this module.
- ctx.ModuleErrorf("internal error: module %q does not depend on a `deapexer` module for prebuilt_apex %q",
- j.Name(), ai.ApexVariationName)
- return
- }
-
// Get the path of the dex implementation jar from the `deapexer` module.
- di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo)
+ di := android.FindDeapexerProviderForModule(ctx)
+ if di == nil {
+ return // An error has been reported by FindDeapexerProviderForModule.
+ }
if dexOutputPath := di.PrebuiltExportPath(apexRootRelativePathToJavaLib(j.BaseModuleName())); dexOutputPath != nil {
- j.dexJarFile = dexOutputPath
+ dexJarFile := makeDexJarPathFromPath(dexOutputPath)
+ j.dexJarFile = dexJarFile
+ installPath := android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, apexRootRelativePathToJavaLib(j.BaseModuleName()))
+ j.dexJarInstallFile = installPath
+
+ j.dexpreopter.installPath = j.dexpreopter.getInstallPath(ctx, installPath)
+ setUncompressDex(ctx, &j.dexpreopter, &j.dexer)
+ j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
+ j.dexpreopt(ctx, dexOutputPath)
// Initialize the hiddenapi structure.
- j.initHiddenAPI(ctx, dexOutputPath, outputFile, nil)
+ j.initHiddenAPI(ctx, dexJarFile, outputFile, j.dexProperties.Uncompress_dex)
} else {
// This should never happen as a variant for a prebuilt_apex is only created if the
// prebuilt_apex has been configured to export the java library dex file.
- ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt_apex %q", deapexerModule.Name())
+ ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt APEX %s", di.ApexModuleName())
}
} else if Bool(j.dexProperties.Compile_dex) {
sdkDep := decodeSdkDep(ctx, android.SdkContext(j))
@@ -1355,11 +1663,9 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// Dex compilation
- j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", jarName)
- if j.dexProperties.Uncompress_dex == nil {
- // If the value was not force-set by the user, use reasonable default based on the module.
- j.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter))
- }
+ j.dexpreopter.installPath = j.dexpreopter.getInstallPath(
+ ctx, android.PathForModuleInstall(ctx, "framework", jarName))
+ setUncompressDex(ctx, &j.dexpreopter, &j.dexer)
j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
var dexOutputFile android.OutputPath
@@ -1369,12 +1675,13 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
// Initialize the hiddenapi structure.
- j.initHiddenAPI(ctx, dexOutputFile, outputFile, j.dexProperties.Uncompress_dex)
+ j.initHiddenAPI(ctx, makeDexJarPathFromPath(dexOutputFile), outputFile, j.dexProperties.Uncompress_dex)
// Encode hidden API flags in dex file.
dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile)
- j.dexJarFile = dexOutputFile
+ j.dexJarFile = makeDexJarPathFromPath(dexOutputFile)
+ j.dexJarInstallFile = android.PathForModuleInstall(ctx, "framework", jarName)
}
}
@@ -1411,12 +1718,12 @@ func (j *Import) ImplementationAndResourcesJars() android.Paths {
return android.Paths{j.combinedClasspathFile}
}
-func (j *Import) DexJarBuildPath() android.Path {
+func (j *Import) DexJarBuildPath() OptionalDexJarPath {
return j.dexJarFile
}
func (j *Import) DexJarInstallPath() android.Path {
- return nil
+ return j.dexJarInstallFile
}
func (j *Import) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap {
@@ -1440,12 +1747,8 @@ func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
if sdkSpec.Kind == android.SdkCore {
return nil
}
- ver, err := sdkSpec.EffectiveVersion(ctx)
- if err != nil {
- return err
- }
- if ver.GreaterThan(sdkVersion) {
- return fmt.Errorf("newer SDK(%v)", ver)
+ if sdkSpec.ApiLevel.GreaterThan(sdkVersion) {
+ return fmt.Errorf("newer SDK(%v)", sdkSpec.ApiLevel)
}
return nil
}
@@ -1478,9 +1781,6 @@ var _ android.IDEInfo = (*Import)(nil)
var _ android.IDECustomizedModuleName = (*Import)(nil)
// Collect information for opening IDE project files in java/jdeps.go.
-const (
- removedPrefix = "prebuilt_"
-)
func (j *Import) IDEInfo(dpInfo *android.IdeInfo) {
dpInfo.Jars = append(dpInfo.Jars, j.PrebuiltSrcs()...)
@@ -1490,11 +1790,7 @@ func (j *Import) IDECustomizedModuleName() string {
// TODO(b/113562217): Extract the base module name from the Import name, often the Import name
// has a prefix "prebuilt_". Remove the prefix explicitly if needed until we find a better
// solution to get the Import name.
- name := j.Name()
- if strings.HasPrefix(name, removedPrefix) {
- name = strings.TrimPrefix(name, removedPrefix)
- }
- return name
+ return android.RemoveOptionalPrebuiltPrefix(j.Name())
}
var _ android.PrebuiltInterface = (*Import)(nil)
@@ -1503,7 +1799,7 @@ func (j *Import) IsInstallable() bool {
return Bool(j.properties.Installable)
}
-var _ dexpreopterInterface = (*Import)(nil)
+var _ DexpreopterInterface = (*Import)(nil)
// java_import imports one or more `.jar` files into the build graph as if they were built by a java_library module.
//
@@ -1527,6 +1823,7 @@ func ImportFactory() android.Module {
android.InitPrebuiltModule(module, &module.properties.Jars)
android.InitApexModule(module)
android.InitSdkAwareModule(module)
+ android.InitBazelModule(module)
InitJavaModule(module, android.HostAndDeviceSupported)
return module
}
@@ -1543,6 +1840,7 @@ func ImportFactoryHost() android.Module {
android.InitPrebuiltModule(module, &module.properties.Jars)
android.InitApexModule(module)
+ android.InitBazelModule(module)
InitJavaModule(module, android.HostSupported)
return module
}
@@ -1564,7 +1862,7 @@ type DexImport struct {
properties DexImportProperties
- dexJarFile android.Path
+ dexJarFile OptionalDexJarPath
dexpreopter
@@ -1616,7 +1914,8 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.hideApexVariantFromMake = true
}
- j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
+ j.dexpreopter.installPath = j.dexpreopter.getInstallPath(
+ ctx, android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar"))
j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
inputJar := ctx.ExpandSource(j.properties.Jars[0], "jars")
@@ -1654,7 +1953,7 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
})
}
- j.dexJarFile = dexOutputFile
+ j.dexJarFile = makeDexJarPathFromPath(dexOutputFile)
j.dexpreopt(ctx, dexOutputFile)
@@ -1664,7 +1963,7 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
}
-func (j *DexImport) DexJarBuildPath() android.Path {
+func (j *DexImport) DexJarBuildPath() OptionalDexJarPath {
return j.dexJarFile
}
@@ -1738,6 +2037,7 @@ func DefaultsFactory() android.Module {
module.AddProperties(
&CommonProperties{},
&DeviceProperties{},
+ &OverridableDeviceProperties{},
&DexProperties{},
&DexpreoptProperties{},
&android.ProtoProperties{},
@@ -1796,32 +2096,30 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.Module,
return
}
- // Find out if the dependency is either an SDK library or an ordinary library that is disguised
- // as an SDK library by the means of `provides_uses_lib` property. If yes, the library is itself
- // a <uses-library> and should be added as a node in the CLC tree, and its CLC should be added
- // as subtree of that node. Otherwise the library is not a <uses_library> and should not be
- // added to CLC, but the transitive <uses-library> dependencies from its CLC should be added to
- // the current CLC.
- var implicitSdkLib *string
- comp, isComp := depModule.(SdkLibraryComponentDependency)
- if isComp {
- implicitSdkLib = comp.OptionalImplicitSdkLibrary()
- // OptionalImplicitSdkLibrary() may be nil so need to fall through to ProvidesUsesLib().
- }
- if implicitSdkLib == nil {
- if ulib, ok := depModule.(ProvidesUsesLib); ok {
- implicitSdkLib = ulib.ProvidesUsesLib()
- }
+ depName := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(depModule))
+
+ var sdkLib *string
+ if lib, ok := depModule.(SdkLibraryDependency); ok && lib.sharedLibrary() {
+ // A shared SDK library. This should be added as a top-level CLC element.
+ sdkLib = &depName
+ } else if ulib, ok := depModule.(ProvidesUsesLib); ok {
+ // A non-SDK library disguised as an SDK library by the means of `provides_uses_lib`
+ // property. This should be handled in the same way as a shared SDK library.
+ sdkLib = ulib.ProvidesUsesLib()
}
depTag := ctx.OtherModuleDependencyTag(depModule)
- if depTag == libTag || depTag == usesLibTag {
+ if depTag == libTag {
// Ok, propagate <uses-library> through non-static library dependencies.
+ } else if tag, ok := depTag.(usesLibraryDependencyTag); ok &&
+ tag.sdkVersion == dexpreopt.AnySdkVersion && tag.implicit {
+ // Ok, propagate <uses-library> through non-compatibility implicit <uses-library>
+ // dependencies.
} else if depTag == staticLibTag {
// Propagate <uses-library> through static library dependencies, unless it is a component
// library (such as stubs). Component libraries have a dependency on their SDK library,
// which should not be pulled just because of a static component library.
- if implicitSdkLib != nil {
+ if sdkLib != nil {
return
}
} else {
@@ -1829,11 +2127,260 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.Module,
return
}
- if implicitSdkLib != nil {
- clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *implicitSdkLib,
- dep.DexJarBuildPath(), dep.DexJarInstallPath(), dep.ClassLoaderContexts())
+ // If this is an SDK (or SDK-like) library, then it should be added as a node in the CLC tree,
+ // and its CLC should be added as subtree of that node. Otherwise the library is not a
+ // <uses_library> and should not be added to CLC, but the transitive <uses-library> dependencies
+ // from its CLC should be added to the current CLC.
+ if sdkLib != nil {
+ clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *sdkLib, false, true,
+ dep.DexJarBuildPath().PathOrNil(), dep.DexJarInstallPath(), dep.ClassLoaderContexts())
} else {
- depName := ctx.OtherModuleName(depModule)
clcMap.AddContextMap(dep.ClassLoaderContexts(), depName)
}
}
+
+type javaCommonAttributes struct {
+ Srcs bazel.LabelListAttribute
+ Plugins bazel.LabelListAttribute
+ Javacopts bazel.StringListAttribute
+}
+
+type javaDependencyLabels struct {
+ // Dependencies which DO NOT contribute to the API visible to upstream dependencies.
+ Deps bazel.LabelListAttribute
+ // Dependencies which DO contribute to the API visible to upstream dependencies.
+ StaticDeps bazel.LabelListAttribute
+}
+
+// convertLibraryAttrsBp2Build converts a few shared attributes from java_* modules
+// and also separates dependencies into dynamic dependencies and static dependencies.
+// Each corresponding Bazel target type, can have a different method for handling
+// dynamic vs. static dependencies, and so these are returned to the calling function.
+type eventLogTagsAttributes struct {
+ Srcs bazel.LabelListAttribute
+}
+
+func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) (*javaCommonAttributes, *javaDependencyLabels) {
+ var srcs bazel.LabelListAttribute
+ archVariantProps := m.GetArchVariantProperties(ctx, &CommonProperties{})
+ for axis, configToProps := range archVariantProps {
+ for config, _props := range configToProps {
+ if archProps, ok := _props.(*CommonProperties); ok {
+ archSrcs := android.BazelLabelForModuleSrcExcludes(ctx, archProps.Srcs, archProps.Exclude_srcs)
+ srcs.SetSelectValue(axis, config, archSrcs)
+ }
+ }
+ }
+
+ javaSrcPartition := "java"
+ protoSrcPartition := "proto"
+ logtagSrcPartition := "logtag"
+ srcPartitions := bazel.PartitionLabelListAttribute(ctx, &srcs, bazel.LabelPartitions{
+ javaSrcPartition: bazel.LabelPartition{Extensions: []string{".java"}, Keep_remainder: true},
+ logtagSrcPartition: bazel.LabelPartition{Extensions: []string{".logtags", ".logtag"}},
+ protoSrcPartition: android.ProtoSrcLabelPartition,
+ })
+
+ javaSrcs := srcPartitions[javaSrcPartition]
+
+ var logtagsSrcs bazel.LabelList
+ if !srcPartitions[logtagSrcPartition].IsEmpty() {
+ logtagsLibName := m.Name() + "_logtags"
+ logtagsSrcs = bazel.MakeLabelList([]bazel.Label{{Label: ":" + logtagsLibName}})
+ ctx.CreateBazelTargetModule(
+ bazel.BazelTargetModuleProperties{
+ Rule_class: "event_log_tags",
+ Bzl_load_location: "//build/make/tools:event_log_tags.bzl",
+ },
+ android.CommonAttributes{Name: logtagsLibName},
+ &eventLogTagsAttributes{
+ Srcs: srcPartitions[logtagSrcPartition],
+ },
+ )
+ }
+ javaSrcs.Append(bazel.MakeLabelListAttribute(logtagsSrcs))
+
+ var javacopts []string
+ if m.properties.Javacflags != nil {
+ javacopts = append(javacopts, m.properties.Javacflags...)
+ }
+ epEnabled := m.properties.Errorprone.Enabled
+ //TODO(b/227504307) add configuration that depends on RUN_ERROR_PRONE environment variable
+ if Bool(epEnabled) {
+ javacopts = append(javacopts, m.properties.Errorprone.Javacflags...)
+ }
+
+ commonAttrs := &javaCommonAttributes{
+ Srcs: javaSrcs,
+ Plugins: bazel.MakeLabelListAttribute(
+ android.BazelLabelForModuleDeps(ctx, m.properties.Plugins),
+ ),
+ Javacopts: bazel.MakeStringListAttribute(javacopts),
+ }
+
+ depLabels := &javaDependencyLabels{}
+
+ var deps bazel.LabelList
+ if m.properties.Libs != nil {
+ deps.Append(android.BazelLabelForModuleDeps(ctx, m.properties.Libs))
+ }
+
+ var staticDeps bazel.LabelList
+ if m.properties.Static_libs != nil {
+ staticDeps.Append(android.BazelLabelForModuleDeps(ctx, m.properties.Static_libs))
+ }
+
+ protoDepLabel := bp2buildProto(ctx, &m.Module, srcPartitions[protoSrcPartition])
+ // Soong does not differentiate between a java_library and the Bazel equivalent of
+ // a java_proto_library + proto_library pair. Instead, in Soong proto sources are
+ // listed directly in the srcs of a java_library, and the classes produced
+ // by protoc are included directly in the resulting JAR. Thus upstream dependencies
+ // that depend on a java_library with proto sources can link directly to the protobuf API,
+ // and so this should be a static dependency.
+ staticDeps.Add(protoDepLabel)
+
+ depLabels.Deps = bazel.MakeLabelListAttribute(deps)
+ depLabels.StaticDeps = bazel.MakeLabelListAttribute(staticDeps)
+
+ return commonAttrs, depLabels
+}
+
+type javaLibraryAttributes struct {
+ *javaCommonAttributes
+ Deps bazel.LabelListAttribute
+ Exports bazel.LabelListAttribute
+}
+
+func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) {
+ commonAttrs, depLabels := m.convertLibraryAttrsBp2Build(ctx)
+
+ deps := depLabels.Deps
+ if !commonAttrs.Srcs.IsEmpty() {
+ deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them
+
+ sdkVersion := m.SdkVersion(ctx)
+ if sdkVersion.Kind == android.SdkPublic && sdkVersion.ApiLevel == android.FutureApiLevel {
+ // TODO(b/220869005) remove forced dependency on current public android.jar
+ deps.Add(bazel.MakeLabelAttribute("//prebuilts/sdk:public_current_android_sdk_java_import"))
+ }
+ } else if !depLabels.Deps.IsEmpty() {
+ ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.")
+ }
+
+ attrs := &javaLibraryAttributes{
+ javaCommonAttributes: commonAttrs,
+ Deps: deps,
+ Exports: depLabels.StaticDeps,
+ }
+
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "java_library",
+ Bzl_load_location: "//build/bazel/rules/java:library.bzl",
+ }
+
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+}
+
+type javaBinaryHostAttributes struct {
+ *javaCommonAttributes
+ Deps bazel.LabelListAttribute
+ Runtime_deps bazel.LabelListAttribute
+ Main_class string
+ Jvm_flags bazel.StringListAttribute
+}
+
+// JavaBinaryHostBp2Build is for java_binary_host bp2build.
+func javaBinaryHostBp2Build(ctx android.TopDownMutatorContext, m *Binary) {
+ commonAttrs, depLabels := m.convertLibraryAttrsBp2Build(ctx)
+
+ deps := depLabels.Deps
+ deps.Append(depLabels.StaticDeps)
+ if m.binaryProperties.Jni_libs != nil {
+ deps.Append(bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, m.binaryProperties.Jni_libs)))
+ }
+
+ var runtimeDeps bazel.LabelListAttribute
+ if commonAttrs.Srcs.IsEmpty() {
+ // if there are no sources, then the dependencies can only be used at runtime
+ runtimeDeps = deps
+ deps = bazel.LabelListAttribute{}
+ }
+
+ mainClass := ""
+ if m.binaryProperties.Main_class != nil {
+ mainClass = *m.binaryProperties.Main_class
+ }
+ if m.properties.Manifest != nil {
+ mainClassInManifest, err := android.GetMainClassInManifest(ctx.Config(), android.PathForModuleSrc(ctx, *m.properties.Manifest).String())
+ if err != nil {
+ return
+ }
+ mainClass = mainClassInManifest
+ }
+
+ attrs := &javaBinaryHostAttributes{
+ javaCommonAttributes: commonAttrs,
+ Deps: deps,
+ Runtime_deps: runtimeDeps,
+ Main_class: mainClass,
+ }
+
+ // Attribute jvm_flags
+ if m.binaryProperties.Jni_libs != nil {
+ jniLibPackages := map[string]bool{}
+ for _, jniLibLabel := range android.BazelLabelForModuleDeps(ctx, m.binaryProperties.Jni_libs).Includes {
+ jniLibPackage := jniLibLabel.Label
+ indexOfColon := strings.Index(jniLibLabel.Label, ":")
+ if indexOfColon > 0 {
+ // JNI lib from other package
+ jniLibPackage = jniLibLabel.Label[2:indexOfColon]
+ } else if indexOfColon == 0 {
+ // JNI lib in the same package of java_binary
+ packageOfCurrentModule := m.GetBazelLabel(ctx, m)
+ jniLibPackage = packageOfCurrentModule[2:strings.Index(packageOfCurrentModule, ":")]
+ }
+ if _, inMap := jniLibPackages[jniLibPackage]; !inMap {
+ jniLibPackages[jniLibPackage] = true
+ }
+ }
+ jniLibPaths := []string{}
+ for jniLibPackage, _ := range jniLibPackages {
+ // See cs/f:.*/third_party/bazel/.*java_stub_template.txt for the use of RUNPATH
+ jniLibPaths = append(jniLibPaths, "$${RUNPATH}"+jniLibPackage)
+ }
+ attrs.Jvm_flags = bazel.MakeStringListAttribute([]string{"-Djava.library.path=" + strings.Join(jniLibPaths, ":")})
+ }
+
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "java_binary",
+ }
+
+ // Create the BazelTargetModule.
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+}
+
+type bazelJavaImportAttributes struct {
+ Jars bazel.LabelListAttribute
+}
+
+// java_import bp2Build converter.
+func (i *Import) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ var jars bazel.LabelListAttribute
+ archVariantProps := i.GetArchVariantProperties(ctx, &ImportProperties{})
+ for axis, configToProps := range archVariantProps {
+ for config, _props := range configToProps {
+ if archProps, ok := _props.(*ImportProperties); ok {
+ archJars := android.BazelLabelForModuleSrcExcludes(ctx, archProps.Jars, []string(nil))
+ jars.SetSelectValue(axis, config, archJars)
+ }
+ }
+ }
+
+ attrs := &bazelJavaImportAttributes{
+ Jars: jars,
+ }
+ props := bazel.BazelTargetModuleProperties{Rule_class: "java_import"}
+
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: android.RemoveOptionalPrebuiltPrefix(i.Name())}, attrs)
+
+}
diff --git a/java/java_test.go b/java/java_test.go
index bd373c177..af889ccd4 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -441,7 +441,7 @@ func TestBinary(t *testing.T) {
}
`)
- buildOS := android.BuildOs.String()
+ buildOS := ctx.Config().BuildOS.String()
bar := ctx.ModuleForTests("bar", buildOS+"_common")
barJar := bar.Output("bar.jar").Output.String()
@@ -478,7 +478,7 @@ func TestTest(t *testing.T) {
}
`)
- buildOS := android.BuildOs.String()
+ buildOS := ctx.Config().BuildOS.String()
foo := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost)
@@ -523,7 +523,7 @@ func TestHostBinaryNoJavaDebugInfoOverride(t *testing.T) {
}
// check that -g is not overridden for host modules
- buildOS := android.BuildOs.String()
+ buildOS := result.Config.BuildOS.String()
hostBinary := result.ModuleForTests("host_binary", buildOS+"_common")
hostJavaFlags := hostBinary.Module().VariablesForTests()["javacFlags"]
if strings.Contains(hostJavaFlags, "-g:source,lines") {
@@ -600,8 +600,8 @@ func TestPrebuilts(t *testing.T) {
}
barDexJar := barModule.Module().(*Import).DexJarBuildPath()
- if barDexJar != nil {
- t.Errorf("bar dex jar build path expected to be nil, got %q", barDexJar)
+ if barDexJar.IsSet() {
+ t.Errorf("bar dex jar build path expected to be set, got %s", barDexJar)
}
if !strings.Contains(javac.Args["classpath"], sdklibStubsJar.String()) {
@@ -612,7 +612,7 @@ func TestPrebuilts(t *testing.T) {
t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, bazJar.String())
}
- bazDexJar := bazModule.Module().(*Import).DexJarBuildPath()
+ bazDexJar := bazModule.Module().(*Import).DexJarBuildPath().Path()
expectedDexJar := "out/soong/.intermediates/baz/android_common/dex/baz.jar"
android.AssertPathRelativeToTopEquals(t, "baz dex jar build path", expectedDexJar, bazDexJar)
@@ -973,7 +973,7 @@ func TestTurbine(t *testing.T) {
fooHeaderJar := filepath.Join("out", "soong", ".intermediates", "foo", "android_common", "turbine-combined", "foo.jar")
barTurbineJar := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine", "bar.jar")
- android.AssertStringDoesContain(t, "bar turbine classpath", barTurbine.Args["classpath"], fooHeaderJar)
+ android.AssertStringDoesContain(t, "bar turbine classpath", barTurbine.Args["turbineFlags"], fooHeaderJar)
android.AssertStringDoesContain(t, "bar javac classpath", barJavac.Args["classpath"], fooHeaderJar)
android.AssertPathsRelativeToTopEquals(t, "bar turbine combineJar", []string{barTurbineJar, fooHeaderJar}, barTurbineCombined.Inputs)
android.AssertStringDoesContain(t, "baz javac classpath", bazJavac.Args["classpath"], "prebuilts/sdk/14/public/android.jar")
@@ -988,69 +988,15 @@ func TestSharding(t *testing.T) {
}
`)
- barHeaderJar := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar")
+ barHeaderJar := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine", "bar.jar")
for i := 0; i < 3; i++ {
barJavac := ctx.ModuleForTests("bar", "android_common").Description("javac" + strconv.Itoa(i))
- if !strings.Contains(barJavac.Args["classpath"], barHeaderJar) {
- t.Errorf("bar javac classpath %v does not contain %q", barJavac.Args["classpath"], barHeaderJar)
+ if !strings.HasPrefix(barJavac.Args["classpath"], "-classpath "+barHeaderJar+":") {
+ t.Errorf("bar javac classpath %v does start with %q", barJavac.Args["classpath"], barHeaderJar)
}
}
}
-func TestJarGenrules(t *testing.T) {
- ctx, _ := testJava(t, `
- java_library {
- name: "foo",
- srcs: ["a.java"],
- }
-
- java_genrule {
- name: "jargen",
- tool_files: ["b.java"],
- cmd: "$(location b.java) $(in) $(out)",
- out: ["jargen.jar"],
- srcs: [":foo"],
- }
-
- java_library {
- name: "bar",
- static_libs: ["jargen"],
- srcs: ["c.java"],
- }
-
- java_library {
- name: "baz",
- libs: ["jargen"],
- srcs: ["c.java"],
- }
- `)
-
- foo := ctx.ModuleForTests("foo", "android_common").Output("javac/foo.jar")
- jargen := ctx.ModuleForTests("jargen", "android_common").Output("jargen.jar")
- bar := ctx.ModuleForTests("bar", "android_common").Output("javac/bar.jar")
- baz := ctx.ModuleForTests("baz", "android_common").Output("javac/baz.jar")
- barCombined := ctx.ModuleForTests("bar", "android_common").Output("combined/bar.jar")
-
- if g, w := jargen.Implicits.Strings(), foo.Output.String(); !android.InList(w, g) {
- t.Errorf("expected jargen inputs [%q], got %q", w, g)
- }
-
- if !strings.Contains(bar.Args["classpath"], jargen.Output.String()) {
- t.Errorf("bar classpath %v does not contain %q", bar.Args["classpath"], jargen.Output.String())
- }
-
- if !strings.Contains(baz.Args["classpath"], jargen.Output.String()) {
- t.Errorf("baz classpath %v does not contain %q", baz.Args["classpath"], jargen.Output.String())
- }
-
- if len(barCombined.Inputs) != 2 ||
- barCombined.Inputs[0].String() != bar.Output.String() ||
- barCombined.Inputs[1].String() != jargen.Output.String() {
- t.Errorf("bar combined jar inputs %v is not [%q, %q]",
- barCombined.Inputs.Strings(), bar.Output.String(), jargen.Output.String())
- }
-}
-
func TestExcludeFileGroupInSrcs(t *testing.T) {
ctx, _ := testJava(t, `
java_library {
@@ -1183,7 +1129,7 @@ func checkPatchModuleFlag(t *testing.T, ctx *android.TestContext, moduleName str
break
}
}
- if expected != android.StringPathRelativeToTop(ctx.Config().BuildDir(), got) {
+ if expected != android.StringPathRelativeToTop(ctx.Config().SoongOutDir(), got) {
t.Errorf("Unexpected patch-module flag for module %q - expected %q, but got %q", moduleName, expected, got)
}
}
@@ -1357,6 +1303,72 @@ func TestAidlFlagsArePassedToTheAidlCompiler(t *testing.T) {
}
}
+func TestAidlFlagsWithMinSdkVersion(t *testing.T) {
+ fixture := android.GroupFixturePreparers(
+ prepareForJavaTest, FixtureWithPrebuiltApis(map[string][]string{"14": {"foo"}}))
+
+ for _, tc := range []struct {
+ name string
+ sdkVersion string
+ expected string
+ }{
+ {"default is current", "", "current"},
+ {"use sdk_version", `sdk_version: "14"`, "14"},
+ {"system_current", `sdk_version: "system_current"`, "current"},
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ ctx := fixture.RunTestWithBp(t, `
+ java_library {
+ name: "foo",
+ srcs: ["aidl/foo/IFoo.aidl"],
+ `+tc.sdkVersion+`
+ }
+ `)
+ aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command
+ expectedAidlFlag := "--min_sdk_version=" + tc.expected
+ if !strings.Contains(aidlCommand, expectedAidlFlag) {
+ t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
+ }
+ })
+ }
+}
+
+func TestAidlEnforcePermissions(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: ["aidl/foo/IFoo.aidl"],
+ aidl: { enforce_permissions: true },
+ }
+ `)
+
+ aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command
+ expectedAidlFlag := "-Wmissing-permission-annotation -Werror"
+ if !strings.Contains(aidlCommand, expectedAidlFlag) {
+ t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
+ }
+}
+
+func TestAidlEnforcePermissionsException(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: ["aidl/foo/IFoo.aidl", "aidl/foo/IFoo2.aidl"],
+ aidl: { enforce_permissions: true, enforce_permissions_exceptions: ["aidl/foo/IFoo2.aidl"] },
+ }
+ `)
+
+ aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command
+ expectedAidlFlag := "$$FLAGS -Wmissing-permission-annotation -Werror aidl/foo/IFoo.aidl"
+ if !strings.Contains(aidlCommand, expectedAidlFlag) {
+ t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
+ }
+ expectedAidlFlag = "$$FLAGS aidl/foo/IFoo2.aidl"
+ if !strings.Contains(aidlCommand, expectedAidlFlag) {
+ t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
+ }
+}
+
func TestDataNativeBinaries(t *testing.T) {
ctx, _ := testJava(t, `
java_test_host {
@@ -1371,7 +1383,7 @@ func TestDataNativeBinaries(t *testing.T) {
}
`)
- buildOS := android.BuildOs.String()
+ buildOS := ctx.Config().BuildOS.String()
test := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost)
entries := android.AndroidMkEntriesForTest(t, ctx, test)[0]
@@ -1387,8 +1399,271 @@ func TestDefaultInstallable(t *testing.T) {
}
`)
- buildOS := android.BuildOs.String()
+ buildOS := ctx.Config().BuildOS.String()
module := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost)
assertDeepEquals(t, "Default installable value should be true.", proptools.BoolPtr(true),
module.properties.Installable)
}
+
+func TestErrorproneEnabled(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ errorprone: {
+ enabled: true,
+ },
+ }
+ `)
+
+ javac := ctx.ModuleForTests("foo", "android_common").Description("javac")
+
+ // Test that the errorprone plugins are passed to javac
+ expectedSubstring := "-Xplugin:ErrorProne"
+ if !strings.Contains(javac.Args["javacFlags"], expectedSubstring) {
+ t.Errorf("expected javacFlags to contain %q, got %q", expectedSubstring, javac.Args["javacFlags"])
+ }
+
+ // Modules with errorprone { enabled: true } will include errorprone checks
+ // in the main javac build rule. Only when RUN_ERROR_PRONE is true will
+ // the explicit errorprone build rule be created.
+ errorprone := ctx.ModuleForTests("foo", "android_common").MaybeDescription("errorprone")
+ if errorprone.RuleParams.Description != "" {
+ t.Errorf("expected errorprone build rule to not exist, but it did")
+ }
+}
+
+func TestErrorproneDisabled(t *testing.T) {
+ bp := `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ errorprone: {
+ enabled: false,
+ },
+ }
+ `
+ ctx := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.FixtureMergeEnv(map[string]string{
+ "RUN_ERROR_PRONE": "true",
+ }),
+ ).RunTestWithBp(t, bp)
+
+ javac := ctx.ModuleForTests("foo", "android_common").Description("javac")
+
+ // Test that the errorprone plugins are not passed to javac, like they would
+ // be if enabled was true.
+ expectedSubstring := "-Xplugin:ErrorProne"
+ if strings.Contains(javac.Args["javacFlags"], expectedSubstring) {
+ t.Errorf("expected javacFlags to not contain %q, got %q", expectedSubstring, javac.Args["javacFlags"])
+ }
+
+ // Check that no errorprone build rule is created, like there would be
+ // if enabled was unset and RUN_ERROR_PRONE was true.
+ errorprone := ctx.ModuleForTests("foo", "android_common").MaybeDescription("errorprone")
+ if errorprone.RuleParams.Description != "" {
+ t.Errorf("expected errorprone build rule to not exist, but it did")
+ }
+}
+
+func TestErrorproneEnabledOnlyByEnvironmentVariable(t *testing.T) {
+ bp := `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ }
+ `
+ ctx := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.FixtureMergeEnv(map[string]string{
+ "RUN_ERROR_PRONE": "true",
+ }),
+ ).RunTestWithBp(t, bp)
+
+ javac := ctx.ModuleForTests("foo", "android_common").Description("javac")
+ errorprone := ctx.ModuleForTests("foo", "android_common").Description("errorprone")
+
+ // Check that the errorprone plugins are not passed to javac, because they
+ // will instead be passed to the separate errorprone compilation
+ expectedSubstring := "-Xplugin:ErrorProne"
+ if strings.Contains(javac.Args["javacFlags"], expectedSubstring) {
+ t.Errorf("expected javacFlags to not contain %q, got %q", expectedSubstring, javac.Args["javacFlags"])
+ }
+
+ // Check that the errorprone plugin is enabled
+ if !strings.Contains(errorprone.Args["javacFlags"], expectedSubstring) {
+ t.Errorf("expected errorprone to contain %q, got %q", expectedSubstring, javac.Args["javacFlags"])
+ }
+}
+
+func TestDataDeviceBinsBuildsDeviceBinary(t *testing.T) {
+ testCases := []struct {
+ dataDeviceBinType string
+ depCompileMultilib string
+ variants []string
+ expectedError string
+ }{
+ {
+ dataDeviceBinType: "first",
+ depCompileMultilib: "first",
+ variants: []string{"android_arm64_armv8-a"},
+ },
+ {
+ dataDeviceBinType: "first",
+ depCompileMultilib: "both",
+ variants: []string{"android_arm64_armv8-a"},
+ },
+ {
+ // this is true because our testing framework is set up with
+ // Targets ~ [<64bit target>, <32bit target>], where 64bit is "first"
+ dataDeviceBinType: "first",
+ depCompileMultilib: "32",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ {
+ dataDeviceBinType: "first",
+ depCompileMultilib: "64",
+ variants: []string{"android_arm64_armv8-a"},
+ },
+ {
+ dataDeviceBinType: "both",
+ depCompileMultilib: "both",
+ variants: []string{
+ "android_arm_armv7-a-neon",
+ "android_arm64_armv8-a",
+ },
+ },
+ {
+ dataDeviceBinType: "both",
+ depCompileMultilib: "32",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ {
+ dataDeviceBinType: "both",
+ depCompileMultilib: "64",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ {
+ dataDeviceBinType: "both",
+ depCompileMultilib: "first",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ {
+ dataDeviceBinType: "32",
+ depCompileMultilib: "32",
+ variants: []string{"android_arm_armv7-a-neon"},
+ },
+ {
+ dataDeviceBinType: "32",
+ depCompileMultilib: "first",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ {
+ dataDeviceBinType: "32",
+ depCompileMultilib: "both",
+ variants: []string{"android_arm_armv7-a-neon"},
+ },
+ {
+ dataDeviceBinType: "32",
+ depCompileMultilib: "64",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ {
+ dataDeviceBinType: "64",
+ depCompileMultilib: "64",
+ variants: []string{"android_arm64_armv8-a"},
+ },
+ {
+ dataDeviceBinType: "64",
+ depCompileMultilib: "both",
+ variants: []string{"android_arm64_armv8-a"},
+ },
+ {
+ dataDeviceBinType: "64",
+ depCompileMultilib: "first",
+ variants: []string{"android_arm64_armv8-a"},
+ },
+ {
+ dataDeviceBinType: "64",
+ depCompileMultilib: "32",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ {
+ dataDeviceBinType: "prefer32",
+ depCompileMultilib: "32",
+ variants: []string{"android_arm_armv7-a-neon"},
+ },
+ {
+ dataDeviceBinType: "prefer32",
+ depCompileMultilib: "both",
+ variants: []string{"android_arm_armv7-a-neon"},
+ },
+ {
+ dataDeviceBinType: "prefer32",
+ depCompileMultilib: "first",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ {
+ dataDeviceBinType: "prefer32",
+ depCompileMultilib: "64",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ }
+
+ bpTemplate := `
+ java_test_host {
+ name: "foo",
+ srcs: ["test.java"],
+ data_device_bins_%s: ["bar"],
+ }
+
+ cc_binary {
+ name: "bar",
+ compile_multilib: "%s",
+ }
+ `
+
+ for _, tc := range testCases {
+ bp := fmt.Sprintf(bpTemplate, tc.dataDeviceBinType, tc.depCompileMultilib)
+
+ errorHandler := android.FixtureExpectsNoErrors
+ if tc.expectedError != "" {
+ errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(tc.expectedError)
+ }
+
+ testName := fmt.Sprintf(`data_device_bins_%s with compile_multilib:"%s"`, tc.dataDeviceBinType, tc.depCompileMultilib)
+ t.Run(testName, func(t *testing.T) {
+ ctx := android.GroupFixturePreparers(PrepareForIntegrationTestWithJava).
+ ExtendWithErrorHandler(errorHandler).
+ RunTestWithBp(t, bp)
+ if tc.expectedError != "" {
+ return
+ }
+
+ buildOS := ctx.Config.BuildOS.String()
+ fooVariant := ctx.ModuleForTests("foo", buildOS+"_common")
+ fooMod := fooVariant.Module().(*TestHost)
+ entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, fooMod)[0]
+
+ expectedAutogenConfig := `<option name="push-file" key="bar" value="/data/local/tests/unrestricted/foo/bar" />`
+ autogen := fooVariant.Rule("autogen")
+ if !strings.Contains(autogen.Args["extraConfigs"], expectedAutogenConfig) {
+ t.Errorf("foo extraConfigs %v does not contain %q", autogen.Args["extraConfigs"], expectedAutogenConfig)
+ }
+
+ expectedData := []string{}
+ for _, variant := range tc.variants {
+ barVariant := ctx.ModuleForTests("bar", variant)
+ relocated := barVariant.Output("bar")
+ expectedInput := fmt.Sprintf("out/soong/.intermediates/bar/%s/unstripped/bar", variant)
+ android.AssertPathRelativeToTopEquals(t, "relocation input", expectedInput, relocated.Input)
+
+ expectedData = append(expectedData, fmt.Sprintf("out/soong/.intermediates/bar/%s/bar:bar", variant))
+ }
+
+ actualData := entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"]
+ android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", ctx.Config, expectedData, actualData)
+ })
+ }
+}
diff --git a/java/jdeps.go b/java/jdeps.go
index 0ab2e422b..373433517 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -40,16 +40,11 @@ type jdepsGeneratorSingleton struct {
var _ android.SingletonMakeVarsProvider = (*jdepsGeneratorSingleton)(nil)
const (
- // Environment variables used to modify behavior of this singleton.
- envVariableCollectJavaDeps = "SOONG_COLLECT_JAVA_DEPS"
- jdepsJsonFileName = "module_bp_java_deps.json"
+ jdepsJsonFileName = "module_bp_java_deps.json"
)
func (j *jdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- if !ctx.Config().IsEnvTrue(envVariableCollectJavaDeps) {
- return
- }
-
+ // (b/204397180) Generate module_bp_java_deps.json by default.
moduleInfos := make(map[string]android.IdeInfo)
ctx.VisitAllModules(func(module android.Module) {
@@ -76,6 +71,8 @@ func (j *jdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonCont
dpInfo.Jars = android.FirstUniqueStrings(dpInfo.Jars)
dpInfo.SrcJars = android.FirstUniqueStrings(dpInfo.SrcJars)
dpInfo.Paths = android.FirstUniqueStrings(dpInfo.Paths)
+ dpInfo.Static_libs = android.FirstUniqueStrings(dpInfo.Static_libs)
+ dpInfo.Libs = android.FirstUniqueStrings(dpInfo.Libs)
moduleInfos[name] = dpInfo
mkProvider, ok := module.(android.AndroidMkDataProvider)
diff --git a/java/kotlin.go b/java/kotlin.go
index 3a6fc0f48..903c6249b 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -28,16 +28,20 @@ import (
var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports{Goma: true},
blueprint.RuleParams{
- Command: `rm -rf "$classesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` +
- `mkdir -p "$classesDir" "$srcJarDir" "$emptyDir" && ` +
+ Command: `rm -rf "$classesDir" "$headerClassesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` +
+ `mkdir -p "$classesDir" "$headerClassesDir" "$srcJarDir" "$emptyDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
`${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` +
` --out_dir "$classesDir" --srcs "$out.rsp" --srcs "$srcJarDir/list"` +
` $commonSrcFilesArg --out "$kotlinBuildFile" && ` +
- `${config.KotlincCmd} ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} ` +
- `$kotlincFlags -jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile ` +
- `-kotlin-home $emptyDir && ` +
- `${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir && ` +
+ `${config.KotlincCmd} ${config.KotlincGlobalFlags} ` +
+ ` ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} ` +
+ ` $kotlincFlags -jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile ` +
+ ` -kotlin-home $emptyDir ` +
+ ` -Xplugin=${config.KotlinAbiGenPluginJar} ` +
+ ` -P plugin:org.jetbrains.kotlin.jvm.abi:outputDir=$headerClassesDir && ` +
+ `${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir -write_if_changed && ` +
+ `${config.SoongZipCmd} -jar -o $headerJar -C $headerClassesDir -D $headerClassesDir -write_if_changed && ` +
`rm -rf "$srcJarDir"`,
CommandDeps: []string{
"${config.KotlincCmd}",
@@ -48,15 +52,17 @@ var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports
"${config.KotlinStdlibJar}",
"${config.KotlinTrove4jJar}",
"${config.KotlinAnnotationJar}",
+ "${config.KotlinAbiGenPluginJar}",
"${config.GenKotlinBuildFileCmd}",
"${config.SoongZipCmd}",
"${config.ZipSyncCmd}",
},
Rspfile: "$out.rsp",
RspfileContent: `$in`,
+ Restat: true,
},
"kotlincFlags", "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "classesDir",
- "kotlinJvmTarget", "kotlinBuildFile", "emptyDir", "name")
+ "headerClassesDir", "headerJar", "kotlinJvmTarget", "kotlinBuildFile", "emptyDir", "name")
func kotlinCommonSrcsList(ctx android.ModuleContext, commonSrcFiles android.Paths) android.OptionalPath {
if len(commonSrcFiles) > 0 {
@@ -75,12 +81,13 @@ func kotlinCommonSrcsList(ctx android.ModuleContext, commonSrcFiles android.Path
}
// kotlinCompile takes .java and .kt sources and srcJars, and compiles the .kt sources into a classes jar in outputFile.
-func kotlinCompile(ctx android.ModuleContext, outputFile android.WritablePath,
+func kotlinCompile(ctx android.ModuleContext, outputFile, headerOutputFile android.WritablePath,
srcFiles, commonSrcFiles, srcJars android.Paths,
flags javaBuilderFlags) {
var deps android.Paths
deps = append(deps, flags.kotlincClasspath...)
+ deps = append(deps, flags.kotlincDeps...)
deps = append(deps, srcJars...)
deps = append(deps, commonSrcFiles...)
@@ -95,17 +102,20 @@ func kotlinCompile(ctx android.ModuleContext, outputFile android.WritablePath,
}
ctx.Build(pctx, android.BuildParams{
- Rule: kotlinc,
- Description: "kotlinc",
- Output: outputFile,
- Inputs: srcFiles,
- Implicits: deps,
+ Rule: kotlinc,
+ Description: "kotlinc",
+ Output: outputFile,
+ ImplicitOutput: headerOutputFile,
+ Inputs: srcFiles,
+ Implicits: deps,
Args: map[string]string{
"classpath": flags.kotlincClasspath.FormJavaClassPath(""),
"kotlincFlags": flags.kotlincFlags,
"commonSrcFilesArg": commonSrcFilesArg,
"srcJars": strings.Join(srcJars.Strings(), " "),
"classesDir": android.PathForModuleOut(ctx, "kotlinc", "classes").String(),
+ "headerClassesDir": android.PathForModuleOut(ctx, "kotlinc", "header_classes").String(),
+ "headerJar": headerOutputFile.String(),
"srcJarDir": android.PathForModuleOut(ctx, "kotlinc", "srcJars").String(),
"kotlinBuildFile": android.PathForModuleOut(ctx, "kotlinc-build.xml").String(),
"emptyDir": android.PathForModuleOut(ctx, "kotlinc", "empty").String(),
@@ -116,7 +126,7 @@ func kotlinCompile(ctx android.ModuleContext, outputFile android.WritablePath,
})
}
-var kapt = pctx.AndroidRemoteStaticRule("kapt", android.RemoteRuleSupports{Goma: true},
+var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupports{Goma: true},
blueprint.RuleParams{
Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && ` +
`mkdir -p "$srcJarDir" "$kaptDir/sources" "$kaptDir/classes" && ` +
@@ -124,19 +134,19 @@ var kapt = pctx.AndroidRemoteStaticRule("kapt", android.RemoteRuleSupports{Goma:
`${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` +
` --srcs "$out.rsp" --srcs "$srcJarDir/list"` +
` $commonSrcFilesArg --out "$kotlinBuildFile" && ` +
- `${config.KotlincCmd} ${config.KaptSuppressJDK9Warnings} ${config.KotlincSuppressJDK9Warnings} ` +
+ `${config.KotlincCmd} ${config.KotlincGlobalFlags} ` +
+ `${config.KaptSuppressJDK9Warnings} ${config.KotlincSuppressJDK9Warnings} ` +
`${config.JavacHeapFlags} $kotlincFlags -Xplugin=${config.KotlinKaptJar} ` +
`-P plugin:org.jetbrains.kotlin.kapt3:sources=$kaptDir/sources ` +
`-P plugin:org.jetbrains.kotlin.kapt3:classes=$kaptDir/classes ` +
`-P plugin:org.jetbrains.kotlin.kapt3:stubs=$kaptDir/stubs ` +
`-P plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true ` +
- `-P plugin:org.jetbrains.kotlin.kapt3:aptMode=stubsAndApt ` +
+ `-P plugin:org.jetbrains.kotlin.kapt3:aptMode=stubs ` +
`-P plugin:org.jetbrains.kotlin.kapt3:javacArguments=$encodedJavacFlags ` +
`$kaptProcessorPath ` +
`$kaptProcessor ` +
`-Xbuild-file=$kotlinBuildFile && ` +
- `${config.SoongZipCmd} -jar -o $out -C $kaptDir/sources -D $kaptDir/sources && ` +
- `${config.SoongZipCmd} -jar -o $classesJarOut -C $kaptDir/classes -D $kaptDir/classes && ` +
+ `${config.SoongZipCmd} -jar -o $out -C $kaptDir/stubs -D $kaptDir/stubs && ` +
`rm -rf "$srcJarDir"`,
CommandDeps: []string{
"${config.KotlincCmd}",
@@ -165,6 +175,7 @@ func kotlinKapt(ctx android.ModuleContext, srcJarOutputFile, resJarOutputFile an
var deps android.Paths
deps = append(deps, flags.kotlincClasspath...)
+ deps = append(deps, flags.kotlincDeps...)
deps = append(deps, srcJars...)
deps = append(deps, flags.processorPath...)
deps = append(deps, commonSrcFiles...)
@@ -194,13 +205,14 @@ func kotlinKapt(ctx android.ModuleContext, srcJarOutputFile, resJarOutputFile an
kotlinName := filepath.Join(ctx.ModuleDir(), ctx.ModuleSubDir(), ctx.ModuleName())
kotlinName = strings.ReplaceAll(kotlinName, "/", "__")
+ // First run kapt to generate .java stubs from .kt files
+ kaptStubsJar := android.PathForModuleOut(ctx, "kapt", "stubs.jar")
ctx.Build(pctx, android.BuildParams{
- Rule: kapt,
- Description: "kapt",
- Output: srcJarOutputFile,
- ImplicitOutput: resJarOutputFile,
- Inputs: srcFiles,
- Implicits: deps,
+ Rule: kaptStubs,
+ Description: "kapt stubs",
+ Output: kaptStubsJar,
+ Inputs: srcFiles,
+ Implicits: deps,
Args: map[string]string{
"classpath": flags.kotlincClasspath.FormJavaClassPath(""),
"kotlincFlags": flags.kotlincFlags,
@@ -216,6 +228,11 @@ func kotlinKapt(ctx android.ModuleContext, srcJarOutputFile, resJarOutputFile an
"classesJarOut": resJarOutputFile.String(),
},
})
+
+ // Then run turbine to perform annotation processing on the stubs and any .java srcFiles.
+ javaSrcFiles := srcFiles.FilterByExt(".java")
+ turbineSrcJars := append(android.Paths{kaptStubsJar}, srcJars...)
+ TurbineApt(ctx, srcJarOutputFile, resJarOutputFile, javaSrcFiles, turbineSrcJars, flags)
}
// kapt converts a list of key, value pairs into a base64 encoded Java serialization, which is what kapt expects.
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index 1c146a192..435d78294 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -15,10 +15,11 @@
package java
import (
- "android/soong/android"
"strconv"
"strings"
"testing"
+
+ "android/soong/android"
)
func TestKotlin(t *testing.T) {
@@ -44,6 +45,10 @@ func TestKotlin(t *testing.T) {
fooKotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
fooJavac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
fooJar := ctx.ModuleForTests("foo", "android_common").Output("combined/foo.jar")
+ fooHeaderJar := ctx.ModuleForTests("foo", "android_common").Output("turbine-combined/foo.jar")
+
+ fooKotlincClasses := fooKotlinc.Output
+ fooKotlincHeaderClasses := fooKotlinc.ImplicitOutput
if len(fooKotlinc.Inputs) != 2 || fooKotlinc.Inputs[0].String() != "a.java" ||
fooKotlinc.Inputs[1].String() != "b.kt" {
@@ -54,17 +59,21 @@ func TestKotlin(t *testing.T) {
t.Errorf(`foo inputs %v != ["a.java"]`, fooJavac.Inputs)
}
- if !strings.Contains(fooJavac.Args["classpath"], fooKotlinc.Output.String()) {
+ if !strings.Contains(fooJavac.Args["classpath"], fooKotlincHeaderClasses.String()) {
t.Errorf("foo classpath %v does not contain %q",
- fooJavac.Args["classpath"], fooKotlinc.Output.String())
+ fooJavac.Args["classpath"], fooKotlincHeaderClasses.String())
}
- if !inList(fooKotlinc.Output.String(), fooJar.Inputs.Strings()) {
+ if !inList(fooKotlincClasses.String(), fooJar.Inputs.Strings()) {
t.Errorf("foo jar inputs %v does not contain %q",
- fooJar.Inputs.Strings(), fooKotlinc.Output.String())
+ fooJar.Inputs.Strings(), fooKotlincClasses.String())
+ }
+
+ if !inList(fooKotlincHeaderClasses.String(), fooHeaderJar.Inputs.Strings()) {
+ t.Errorf("foo header jar inputs %v does not contain %q",
+ fooHeaderJar.Inputs.Strings(), fooKotlincHeaderClasses.String())
}
- fooHeaderJar := ctx.ModuleForTests("foo", "android_common").Output("turbine-combined/foo.jar")
bazHeaderJar := ctx.ModuleForTests("baz", "android_common").Output("turbine-combined/baz.jar")
barKotlinc := ctx.ModuleForTests("bar", "android_common").Rule("kotlinc")
@@ -114,53 +123,73 @@ func TestKapt(t *testing.T) {
t.Run("", func(t *testing.T) {
ctx, _ := testJava(t, bp)
- buildOS := android.BuildOs.String()
+ buildOS := ctx.Config().BuildOS.String()
- kapt := ctx.ModuleForTests("foo", "android_common").Rule("kapt")
- kotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
- javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
+ foo := ctx.ModuleForTests("foo", "android_common")
+ kaptStubs := foo.Rule("kapt")
+ turbineApt := foo.Description("turbine apt")
+ kotlinc := foo.Rule("kotlinc")
+ javac := foo.Rule("javac")
bar := ctx.ModuleForTests("bar", buildOS+"_common").Rule("javac").Output.String()
baz := ctx.ModuleForTests("baz", buildOS+"_common").Rule("javac").Output.String()
// Test that the kotlin and java sources are passed to kapt and kotlinc
- if len(kapt.Inputs) != 2 || kapt.Inputs[0].String() != "a.java" || kapt.Inputs[1].String() != "b.kt" {
- t.Errorf(`foo kapt inputs %v != ["a.java", "b.kt"]`, kapt.Inputs)
+ if len(kaptStubs.Inputs) != 2 || kaptStubs.Inputs[0].String() != "a.java" || kaptStubs.Inputs[1].String() != "b.kt" {
+ t.Errorf(`foo kapt inputs %v != ["a.java", "b.kt"]`, kaptStubs.Inputs)
}
if len(kotlinc.Inputs) != 2 || kotlinc.Inputs[0].String() != "a.java" || kotlinc.Inputs[1].String() != "b.kt" {
t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, kotlinc.Inputs)
}
- // Test that only the java sources are passed to javac
+ // Test that only the java sources are passed to turbine-apt and javac
+ if len(turbineApt.Inputs) != 1 || turbineApt.Inputs[0].String() != "a.java" {
+ t.Errorf(`foo turbine apt inputs %v != ["a.java"]`, turbineApt.Inputs)
+ }
if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
}
- // Test that the kapt srcjar is a dependency of kotlinc and javac rules
- if !inList(kapt.Output.String(), kotlinc.Implicits.Strings()) {
- t.Errorf("expected %q in kotlinc implicits %v", kapt.Output.String(), kotlinc.Implicits.Strings())
+ // Test that the kapt stubs jar is a dependency of turbine-apt
+ if !inList(kaptStubs.Output.String(), turbineApt.Implicits.Strings()) {
+ t.Errorf("expected %q in turbine-apt implicits %v", kaptStubs.Output.String(), kotlinc.Implicits.Strings())
+ }
+
+ // Test that the turbine-apt srcjar is a dependency of kotlinc and javac rules
+ if !inList(turbineApt.Output.String(), kotlinc.Implicits.Strings()) {
+ t.Errorf("expected %q in kotlinc implicits %v", turbineApt.Output.String(), kotlinc.Implicits.Strings())
}
- if !inList(kapt.Output.String(), javac.Implicits.Strings()) {
- t.Errorf("expected %q in javac implicits %v", kapt.Output.String(), javac.Implicits.Strings())
+ if !inList(turbineApt.Output.String(), javac.Implicits.Strings()) {
+ t.Errorf("expected %q in javac implicits %v", turbineApt.Output.String(), javac.Implicits.Strings())
}
- // Test that the kapt srcjar is extracted by the kotlinc and javac rules
- if kotlinc.Args["srcJars"] != kapt.Output.String() {
- t.Errorf("expected %q in kotlinc srcjars %v", kapt.Output.String(), kotlinc.Args["srcJars"])
+ // Test that the turbine-apt srcjar is extracted by the kotlinc and javac rules
+ if kotlinc.Args["srcJars"] != turbineApt.Output.String() {
+ t.Errorf("expected %q in kotlinc srcjars %v", turbineApt.Output.String(), kotlinc.Args["srcJars"])
}
- if javac.Args["srcJars"] != kapt.Output.String() {
- t.Errorf("expected %q in javac srcjars %v", kapt.Output.String(), kotlinc.Args["srcJars"])
+ if javac.Args["srcJars"] != turbineApt.Output.String() {
+ t.Errorf("expected %q in javac srcjars %v", turbineApt.Output.String(), kotlinc.Args["srcJars"])
}
// Test that the processors are passed to kapt
expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar +
" -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz
- if kapt.Args["kaptProcessorPath"] != expectedProcessorPath {
- t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kapt.Args["kaptProcessorPath"])
+ if kaptStubs.Args["kaptProcessorPath"] != expectedProcessorPath {
+ t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kaptStubs.Args["kaptProcessorPath"])
}
expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz"
- if kapt.Args["kaptProcessor"] != expectedProcessor {
- t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kapt.Args["kaptProcessor"])
+ if kaptStubs.Args["kaptProcessor"] != expectedProcessor {
+ t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kaptStubs.Args["kaptProcessor"])
+ }
+
+ // Test that the processors are passed to turbine-apt
+ expectedProcessorPath = "--processorpath " + bar + " " + baz
+ if !strings.Contains(turbineApt.Args["turbineFlags"], expectedProcessorPath) {
+ t.Errorf("expected turbine-apt processorpath %q, got %q", expectedProcessorPath, turbineApt.Args["turbineFlags"])
+ }
+ expectedProcessor = "--processors com.bar com.baz"
+ if !strings.Contains(turbineApt.Args["turbineFlags"], expectedProcessor) {
+ t.Errorf("expected turbine-apt processor %q, got %q", expectedProcessor, turbineApt.Args["turbineFlags"])
}
// Test that the processors are not passed to javac
@@ -182,10 +211,9 @@ func TestKapt(t *testing.T) {
android.FixtureMergeEnv(env),
).RunTestWithBp(t, bp)
- buildOS := android.BuildOs.String()
+ buildOS := result.Config.BuildOS.String()
kapt := result.ModuleForTests("foo", "android_common").Rule("kapt")
- //kotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
javac := result.ModuleForTests("foo", "android_common").Description("javac")
errorprone := result.ModuleForTests("foo", "android_common").Description("errorprone")
@@ -281,3 +309,54 @@ func TestKaptEncodeFlags(t *testing.T) {
})
}
}
+
+func TestKotlinCompose(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ ).RunTestWithBp(t, `
+ java_library {
+ name: "androidx.compose.runtime_runtime",
+ }
+
+ java_library_host {
+ name: "androidx.compose.compiler_compiler-hosted",
+ }
+
+ java_library {
+ name: "withcompose",
+ srcs: ["a.kt"],
+ plugins: ["plugin"],
+ static_libs: ["androidx.compose.runtime_runtime"],
+ }
+
+ java_library {
+ name: "nocompose",
+ srcs: ["a.kt"],
+ }
+
+ java_plugin {
+ name: "plugin",
+ }
+ `)
+
+ buildOS := result.Config.BuildOS.String()
+
+ composeCompiler := result.ModuleForTests("androidx.compose.compiler_compiler-hosted", buildOS+"_common").Rule("combineJar").Output
+ withCompose := result.ModuleForTests("withcompose", "android_common")
+ noCompose := result.ModuleForTests("nocompose", "android_common")
+
+ android.AssertStringListContains(t, "missing compose compiler dependency",
+ withCompose.Rule("kotlinc").Implicits.Strings(), composeCompiler.String())
+
+ android.AssertStringDoesContain(t, "missing compose compiler plugin",
+ withCompose.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+composeCompiler.String())
+
+ android.AssertStringListContains(t, "missing kapt compose compiler dependency",
+ withCompose.Rule("kapt").Implicits.Strings(), composeCompiler.String())
+
+ android.AssertStringListDoesNotContain(t, "unexpected compose compiler dependency",
+ noCompose.Rule("kotlinc").Implicits.Strings(), composeCompiler.String())
+
+ android.AssertStringDoesNotContain(t, "unexpected compose compiler plugin",
+ noCompose.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+composeCompiler.String())
+}
diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go
index 628a10048..8e224914d 100644
--- a/java/legacy_core_platform_api_usage.go
+++ b/java/legacy_core_platform_api_usage.go
@@ -81,7 +81,6 @@ var legacyCorePlatformApiModules = []string{
"ds-car-docs", // for AAOS API documentation only
"DynamicSystemInstallationService",
"EmergencyInfo-lib",
- "ethernet-service",
"EthernetServiceTests",
"ExternalStorageProvider",
"face-V1-0-javalib",
@@ -228,17 +227,27 @@ func init() {
}
}
-func useLegacyCorePlatformApi(ctx android.EarlyModuleContext) bool {
- return useLegacyCorePlatformApiByName(ctx.ModuleName())
+var legacyCorePlatformApiLookupKey = android.NewOnceKey("legacyCorePlatformApiLookup")
+
+func getLegacyCorePlatformApiLookup(config android.Config) map[string]struct{} {
+ return config.Once(legacyCorePlatformApiLookupKey, func() interface{} {
+ return legacyCorePlatformApiLookup
+ }).(map[string]struct{})
}
-func useLegacyCorePlatformApiByName(name string) bool {
- _, found := legacyCorePlatformApiLookup[name]
+// useLegacyCorePlatformApi checks to see whether the supplied module name is in the list of modules
+// that are able to use the legacy core platform API and returns true if it does, false otherwise.
+//
+// This method takes the module name separately from the context as this may be being called for a
+// module that is not the target of the supplied context.
+func useLegacyCorePlatformApi(ctx android.EarlyModuleContext, moduleName string) bool {
+ lookup := getLegacyCorePlatformApiLookup(ctx.Config())
+ _, found := lookup[moduleName]
return found
}
func corePlatformSystemModules(ctx android.EarlyModuleContext) string {
- if useLegacyCorePlatformApi(ctx) {
+ if useLegacyCorePlatformApi(ctx, ctx.ModuleName()) {
return config.LegacyCorePlatformSystemModules
} else {
return config.StableCorePlatformSystemModules
@@ -246,7 +255,7 @@ func corePlatformSystemModules(ctx android.EarlyModuleContext) string {
}
func corePlatformBootclasspathLibraries(ctx android.EarlyModuleContext) []string {
- if useLegacyCorePlatformApi(ctx) {
+ if useLegacyCorePlatformApi(ctx, ctx.ModuleName()) {
return config.LegacyCorePlatformBootclasspathLibraries
} else {
return config.StableCorePlatformBootclasspathLibraries
diff --git a/java/lint.go b/java/lint.go
index fe3218e90..426a2af25 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -75,9 +75,9 @@ type linter struct {
extraLintCheckJars android.Paths
test bool
library bool
- minSdkVersion string
- targetSdkVersion string
- compileSdkVersion string
+ minSdkVersion android.ApiLevel
+ targetSdkVersion android.ApiLevel
+ compileSdkVersion android.ApiLevel
compileSdkKind android.SdkKind
javaLanguageLevel string
kotlinLanguageLevel string
@@ -102,12 +102,12 @@ type lintOutputsIntf interface {
lintOutputs() *lintOutputs
}
-type lintDepSetsIntf interface {
+type LintDepSetsIntf interface {
LintDepSets() LintDepSets
// Methods used to propagate strict_updatability_linting values.
- getStrictUpdatabilityLinting() bool
- setStrictUpdatabilityLinting(bool)
+ GetStrictUpdatabilityLinting() bool
+ SetStrictUpdatabilityLinting(bool)
}
type LintDepSets struct {
@@ -158,15 +158,15 @@ func (l *linter) LintDepSets() LintDepSets {
return l.outputs.depSets
}
-func (l *linter) getStrictUpdatabilityLinting() bool {
+func (l *linter) GetStrictUpdatabilityLinting() bool {
return BoolDefault(l.properties.Lint.Strict_updatability_linting, false)
}
-func (l *linter) setStrictUpdatabilityLinting(strictLinting bool) {
+func (l *linter) SetStrictUpdatabilityLinting(strictLinting bool) {
l.properties.Lint.Strict_updatability_linting = &strictLinting
}
-var _ lintDepSetsIntf = (*linter)(nil)
+var _ LintDepSetsIntf = (*linter)(nil)
var _ lintOutputsIntf = (*linter)(nil)
@@ -273,7 +273,7 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.Ru
cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
- if l.getStrictUpdatabilityLinting() {
+ if l.GetStrictUpdatabilityLinting() {
// Verify the module does not baseline issues that endanger safe updatability.
if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
cmd.FlagWithInput("--baseline ", baselinePath.Path())
@@ -300,7 +300,7 @@ func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleB
Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
- l.minSdkVersion, l.targetSdkVersion).
+ l.minSdkVersion.String(), l.targetSdkVersion.String()).
Text(`echo "</manifest>"`).
Text(") >").Output(manifestPath)
@@ -325,7 +325,7 @@ func (l *linter) lint(ctx android.ModuleContext) {
return
}
- if l.minSdkVersion != l.compileSdkVersion {
+ if l.minSdkVersion.CompareTo(l.compileSdkVersion) == -1 {
l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
_, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
if len(filtered) != 0 {
@@ -377,11 +377,12 @@ func (l *linter) lint(ctx android.ModuleContext) {
html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
+ baseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
- if depLint, ok := dep.(lintDepSetsIntf); ok {
+ if depLint, ok := dep.(LintDepSetsIntf); ok {
depSetsBuilder.Transitive(depLint.LintDepSets())
}
})
@@ -426,7 +427,7 @@ func (l *linter) lint(ctx android.ModuleContext) {
FlagWithOutput("--html ", html).
FlagWithOutput("--text ", text).
FlagWithOutput("--xml ", xml).
- FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
+ FlagWithArg("--compile-sdk-version ", l.compileSdkVersion.String()).
FlagWithArg("--java-language-level ", l.javaLanguageLevel).
FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
@@ -447,6 +448,8 @@ func (l *linter) lint(ctx android.ModuleContext) {
cmd.FlagWithInput("--baseline ", lintBaseline.Path())
}
+ cmd.FlagWithOutput("--write-reference-baseline ", baseline)
+
cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
@@ -657,10 +660,10 @@ func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android
// Enforce the strict updatability linting to all applicable transitive dependencies.
func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
m := ctx.Module()
- if d, ok := m.(lintDepSetsIntf); ok && d.getStrictUpdatabilityLinting() {
+ if d, ok := m.(LintDepSetsIntf); ok && d.GetStrictUpdatabilityLinting() {
ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
- if a, ok := d.(lintDepSetsIntf); ok {
- a.setStrictUpdatabilityLinting(true)
+ if a, ok := d.(LintDepSetsIntf); ok {
+ a.SetStrictUpdatabilityLinting(true)
}
})
}
diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt
index 2de05b0a0..1eee354cd 100644
--- a/java/lint_defaults.txt
+++ b/java/lint_defaults.txt
@@ -1,10 +1,42 @@
# Treat LintError as fatal to catch invocation errors
--fatal_check LintError
+# Checks which do not apply to the platform (implementation
+# in lint assumes that it's running on app code)
+
+--disable_check AnimatorKeep
+--disable_check AppBundleLocaleChanges
+--disable_check BlockedPrivateApi
+--disable_check CustomSplashScreen
+--disable_check CustomX509TrustManager
+--disable_check Deprecated
+--disable_check ExifInterface
+--disable_check HardwareIds
+--disable_check InvalidWakeLockTag
+--disable_check LibraryCustomView
+--disable_check MissingPermission
+--disable_check NonConstantResourceId
+--disable_check OldTargetApi
+--disable_check Override
+--disable_check PackageManagerGetSignatures
+--disable_check PrivateApi
+--disable_check ProtectedPermissions
+--disable_check QueryPermissionsNeeded
+--disable_check ScopedStorage
+--disable_check ServiceCast
+--disable_check SoonBlockedPrivateApi
+--disable_check SuspiciousImport
+--disable_check UnusedResources
+--disable_check ViewConstructor
+# Disable NewApi checks for the platform since platform is the one that implements
+# the API. This prevents noisy lint warnings like b/228956345#1
+# NewApi checks will continue to be enforced for apex deps since
+# lint.strict_updatability_linting will be true for those Soong modules
+--disable_check NewApi
+
# Downgrade existing errors to warnings
--warning_check AppCompatResource # 55 occurences in 10 modules
--warning_check AppLinkUrlError # 111 occurences in 53 modules
---warning_check BlockedPrivateApi # 2 occurences in 2 modules
--warning_check ByteOrderMark # 2 occurences in 2 modules
--warning_check DuplicateActivity # 3 occurences in 3 modules
--warning_check DuplicateDefinition # 3623 occurences in 48 modules
@@ -22,9 +54,7 @@
--warning_check Instantiatable # 145 occurences in 19 modules
--warning_check InvalidPermission # 6 occurences in 4 modules
--warning_check InvalidUsesTagAttribute # 6 occurences in 2 modules
---warning_check InvalidWakeLockTag # 111 occurences in 37 modules
--warning_check JavascriptInterface # 3 occurences in 2 modules
---warning_check LibraryCustomView # 9 occurences in 4 modules
--warning_check LogTagMismatch # 81 occurences in 13 modules
--warning_check LongLogTag # 249 occurences in 12 modules
--warning_check MenuTitle # 5 occurences in 4 modules
@@ -35,21 +65,17 @@
--warning_check MissingLeanbackLauncher # 3 occurences in 3 modules
--warning_check MissingLeanbackSupport # 2 occurences in 2 modules
--warning_check MissingOnPlayFromSearch # 1 occurences in 1 modules
---warning_check MissingPermission # 2071 occurences in 150 modules
--warning_check MissingPrefix # 46 occurences in 41 modules
--warning_check MissingQuantity # 100 occurences in 1 modules
--warning_check MissingSuperCall # 121 occurences in 36 modules
--warning_check MissingTvBanner # 3 occurences in 3 modules
--warning_check NamespaceTypo # 3 occurences in 3 modules
--warning_check NetworkSecurityConfig # 46 occurences in 12 modules
---warning_check NewApi # 1996 occurences in 122 modules
--warning_check NotSibling # 15 occurences in 10 modules
--warning_check ObjectAnimatorBinding # 14 occurences in 5 modules
--warning_check OnClick # 49 occurences in 21 modules
--warning_check Orientation # 77 occurences in 19 modules
---warning_check Override # 385 occurences in 36 modules
--warning_check ParcelCreator # 23 occurences in 2 modules
---warning_check ProtectedPermissions # 2413 occurences in 381 modules
--warning_check Range # 80 occurences in 28 modules
--warning_check RecyclerView # 1 occurences in 1 modules
--warning_check ReferenceType # 4 occurences in 1 modules
@@ -60,8 +86,6 @@
--warning_check ResourceType # 137 occurences in 36 modules
--warning_check RestrictedApi # 28 occurences in 5 modules
--warning_check RtlCompat # 9 occurences in 6 modules
---warning_check ServiceCast # 3 occurences in 1 modules
---warning_check SoonBlockedPrivateApi # 5 occurences in 3 modules
--warning_check StringFormatInvalid # 148 occurences in 11 modules
--warning_check StringFormatMatches # 4800 occurences in 30 modules
--warning_check UnknownId # 8 occurences in 7 modules
@@ -74,7 +98,9 @@
--warning_check WrongThread # 14 occurences in 6 modules
--warning_check WrongViewCast # 1 occurences in 1 modules
-# TODO(b/158390965): remove this when lint doesn't crash
---disable_check HardcodedDebugMode
-
+--warning_check CoarseFineLocation
+--warning_check IntentFilterExportedReceiver
--warning_check QueryAllPackagesPermission
+--warning_check RemoteViewLayout
+--warning_check SupportAnnotationUsage
+--warning_check UniqueConstants
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 10739b015..1e2723845 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -32,9 +32,9 @@ func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContex
// The tags used for the dependencies between the platform bootclasspath and any configured boot
// jars.
var (
- platformBootclasspathArtBootJarDepTag = bootclasspathDependencyTag{name: "art-boot-jar"}
- platformBootclasspathNonUpdatableBootJarDepTag = bootclasspathDependencyTag{name: "non-updatable-boot-jar"}
- platformBootclasspathUpdatableBootJarDepTag = bootclasspathDependencyTag{name: "updatable-boot-jar"}
+ platformBootclasspathArtBootJarDepTag = bootclasspathDependencyTag{name: "art-boot-jar"}
+ platformBootclasspathBootJarDepTag = bootclasspathDependencyTag{name: "platform-boot-jar"}
+ platformBootclasspathApexBootJarDepTag = bootclasspathDependencyTag{name: "apex-boot-jar"}
)
type platformBootclasspathModule struct {
@@ -68,7 +68,6 @@ type platformBootclasspathProperties struct {
func platformBootclasspathFactory() android.SingletonModule {
m := &platformBootclasspathModule{}
m.AddProperties(&m.properties)
- // TODO(satayev): split apex jars into separate configs.
initClasspathFragment(m, BOOTCLASSPATH)
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
return m
@@ -131,11 +130,11 @@ func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.Botto
// Add dependencies on all the non-updatable module configured in the "boot" boot image. That does
// not include modules configured in the "art" boot image.
bootImageConfig := b.getImageConfig(ctx)
- addDependenciesOntoBootImageModules(ctx, bootImageConfig.modules, platformBootclasspathNonUpdatableBootJarDepTag)
+ addDependenciesOntoBootImageModules(ctx, bootImageConfig.modules, platformBootclasspathBootJarDepTag)
- // Add dependencies on all the updatable modules.
- updatableModules := dexpreopt.GetGlobalConfig(ctx).UpdatableBootJars
- addDependenciesOntoBootImageModules(ctx, updatableModules, platformBootclasspathUpdatableBootJarDepTag)
+ // Add dependencies on all the apex jars.
+ apexJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
+ addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag)
// Add dependencies on all the fragments.
b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx)
@@ -163,16 +162,16 @@ func (d *platformBootclasspathModule) MakeVars(ctx android.MakeVarsContext) {
}
func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- // Gather all the dependencies from the art, updatable and non-updatable boot jars.
+ // Gather all the dependencies from the art, platform, and apex boot jars.
artModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathArtBootJarDepTag)
- nonUpdatableModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathNonUpdatableBootJarDepTag)
- updatableModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathUpdatableBootJarDepTag)
+ platformModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathBootJarDepTag)
+ apexModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathApexBootJarDepTag)
// Concatenate them all, in order as they would appear on the bootclasspath.
var allModules []android.Module
allModules = append(allModules, artModules...)
- allModules = append(allModules, nonUpdatableModules...)
- allModules = append(allModules, updatableModules...)
+ allModules = append(allModules, platformModules...)
+ allModules = append(allModules, apexModules...)
b.configuredModules = allModules
// Gather all the fragments dependencies.
@@ -180,8 +179,8 @@ func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.Mo
// Check the configuration of the boot modules.
// ART modules are checked by the art-bootclasspath-fragment.
- b.checkNonUpdatableModules(ctx, nonUpdatableModules)
- b.checkUpdatableModules(ctx, updatableModules)
+ b.checkPlatformModules(ctx, platformModules)
+ b.checkApexModules(ctx, apexModules)
b.generateClasspathProtoBuildActions(ctx)
@@ -193,23 +192,40 @@ func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.Mo
return
}
- b.generateBootImageBuildActions(ctx, nonUpdatableModules, updatableModules)
+ b.generateBootImageBuildActions(ctx, platformModules, apexModules)
}
// Generate classpaths.proto config
func (b *platformBootclasspathModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) {
+ configuredJars := b.configuredJars(ctx)
// ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH
- classpathJars := configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), BOOTCLASSPATH, DEX2OATBOOTCLASSPATH)
- b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, classpathJars)
+ classpathJars := configuredJarListToClasspathJars(ctx, configuredJars, BOOTCLASSPATH, DEX2OATBOOTCLASSPATH)
+ b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars)
}
-func (b *platformBootclasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
- return b.getImageConfig(ctx).modules
+func (b *platformBootclasspathModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList {
+ // Include all non APEX jars
+ jars := b.getImageConfig(ctx).modules
+
+ // Include jars from APEXes that don't populate their classpath proto config.
+ remainingJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
+ for _, fragment := range b.fragments {
+ info := ctx.OtherModuleProvider(fragment, ClasspathFragmentProtoContentInfoProvider).(ClasspathFragmentProtoContentInfo)
+ if info.ClasspathFragmentProtoGenerated {
+ remainingJars = remainingJars.RemoveList(info.ClasspathFragmentProtoContents)
+ }
+ }
+ for i := 0; i < remainingJars.Len(); i++ {
+ jars = jars.Append(remainingJars.Apex(i), remainingJars.Jar(i))
+ }
+
+ return jars
}
-// checkNonUpdatableModules ensures that the non-updatable modules supplied are not part of an
-// updatable module.
-func (b *platformBootclasspathModule) checkNonUpdatableModules(ctx android.ModuleContext, modules []android.Module) {
+// checkPlatformModules ensures that the non-updatable modules supplied are not part of an
+// apex module.
+func (b *platformBootclasspathModule) checkPlatformModules(ctx android.ModuleContext, modules []android.Module) {
+ // TODO(satayev): change this check to only allow core-icu4j, all apex jars should not be here.
for _, m := range modules {
apexInfo := ctx.OtherModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
fromUpdatableApex := apexInfo.Updatable
@@ -222,8 +238,8 @@ func (b *platformBootclasspathModule) checkNonUpdatableModules(ctx android.Modul
}
}
-// checkUpdatableModules ensures that the updatable modules supplied are not from the platform.
-func (b *platformBootclasspathModule) checkUpdatableModules(ctx android.ModuleContext, modules []android.Module) {
+// checkApexModules ensures that the apex modules supplied are not from the platform.
+func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext, modules []android.Module) {
for _, m := range modules {
apexInfo := ctx.OtherModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
fromUpdatableApex := apexInfo.Updatable
@@ -239,12 +255,12 @@ func (b *platformBootclasspathModule) checkUpdatableModules(ctx android.ModuleCo
// modules is complete.
if !ctx.Config().AlwaysUsePrebuiltSdks() {
// error: this jar is part of the platform
- ctx.ModuleErrorf("module %q from platform is not allowed in the updatable boot jars list", name)
+ ctx.ModuleErrorf("module %q from platform is not allowed in the apex boot jars list", name)
}
} else {
// TODO(b/177892522): Treat this as an error.
// Cannot do that at the moment because framework-wifi and framework-tethering are in the
- // PRODUCT_UPDATABLE_BOOT_JARS but not marked as updatable in AOSP.
+ // PRODUCT_APEX_BOOT_JARS but not marked as updatable in AOSP.
}
}
}
@@ -299,7 +315,7 @@ func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.
// Generate the monolithic stub-flags.csv file.
stubFlags := hiddenAPISingletonPaths(ctx).stubFlags
- buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags", stubFlags, bootDexJarByModule.bootDexJars(), input, monolithicInfo.StubFlagsPaths)
+ buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags", stubFlags, bootDexJarByModule.bootDexJars(), input, monolithicInfo.StubFlagSubsets)
// Generate the annotation-flags.csv file from all the module annotations.
annotationFlags := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "annotation-flags-from-classes.csv")
@@ -312,7 +328,7 @@ func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.
allAnnotationFlagFiles := android.Paths{annotationFlags}
allAnnotationFlagFiles = append(allAnnotationFlagFiles, monolithicInfo.AnnotationFlagsPaths...)
allFlags := hiddenAPISingletonPaths(ctx).flags
- buildRuleToGenerateHiddenApiFlags(ctx, "hiddenAPIFlagsFile", "monolithic hidden API flags", allFlags, stubFlags, allAnnotationFlagFiles, monolithicInfo.FlagsFilesByCategory, monolithicInfo.AllFlagsPaths, android.OptionalPath{})
+ buildRuleToGenerateHiddenApiFlags(ctx, "hiddenAPIFlagsFile", "monolithic hidden API flags", allFlags, stubFlags, allAnnotationFlagFiles, monolithicInfo.FlagsFilesByCategory, monolithicInfo.FlagSubsets, android.OptionalPath{})
// Generate an intermediate monolithic hiddenapi-metadata.csv file directly from the annotations
// in the source code.
@@ -389,7 +405,7 @@ func (b *platformBootclasspathModule) generateHiddenApiMakeVars(ctx android.Make
}
// generateBootImageBuildActions generates ninja rules related to the boot image creation.
-func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.ModuleContext, nonUpdatableModules, updatableModules []android.Module) {
+func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.ModuleContext, platformModules, apexModules []android.Module) {
// Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
// GenerateSingletonBuildActions method as it cannot create it for itself.
dexpreopt.GetGlobalSoongConfig(ctx)
@@ -407,17 +423,14 @@ func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.
// Generate the framework profile rule
bootFrameworkProfileRule(ctx, imageConfig)
- // Generate the updatable bootclasspath packages rule.
- generateUpdatableBcpPackagesRule(ctx, imageConfig, updatableModules)
-
- // Copy non-updatable module dex jars to their predefined locations.
- nonUpdatableBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, nonUpdatableModules)
- copyBootJarsToPredefinedLocations(ctx, nonUpdatableBootDexJarsByModule, imageConfig.dexPathsByModule)
+ // Copy platform module dex jars to their predefined locations.
+ platformBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, platformModules)
+ copyBootJarsToPredefinedLocations(ctx, platformBootDexJarsByModule, imageConfig.dexPathsByModule)
- // Copy updatable module dex jars to their predefined locations.
- config := GetUpdatableBootConfig(ctx)
- updatableBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, updatableModules)
- copyBootJarsToPredefinedLocations(ctx, updatableBootDexJarsByModule, config.dexPathsByModule)
+ // Copy apex module dex jars to their predefined locations.
+ config := GetApexBootConfig(ctx)
+ apexBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, apexModules)
+ copyBootJarsToPredefinedLocations(ctx, apexBootDexJarsByModule, config.dexPathsByModule)
// Build a profile for the image config and then use that to build the boot image.
profile := bootImageProfileRule(ctx, imageConfig)
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index 712c2a203..f442ddfd4 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -115,7 +115,7 @@ func (p *platformCompatConfig) AndroidMkEntries() []android.AndroidMkEntries {
Include: "$(BUILD_PREBUILT)",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.configFile.Base())
},
},
@@ -134,8 +134,8 @@ type compatConfigMemberType struct {
android.SdkMemberTypeBase
}
-func (b *compatConfigMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
- mctx.AddVariationDependencies(nil, dependencyTag, names...)
+func (b *compatConfigMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ ctx.AddVariationDependencies(nil, dependencyTag, names...)
}
func (b *compatConfigMemberType) IsInstance(module android.Module) bool {
diff --git a/java/plugin.go b/java/plugin.go
index 297ac2cb8..123dbd4c0 100644
--- a/java/plugin.go
+++ b/java/plugin.go
@@ -14,7 +14,10 @@
package java
-import "android/soong/android"
+import (
+ "android/soong/android"
+ "android/soong/bazel"
+)
func init() {
registerJavaPluginBuildComponents(android.InitRegistrationContext)
@@ -24,7 +27,6 @@ func registerJavaPluginBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("java_plugin", PluginFactory)
}
-// A java_plugin module describes a host java library that will be used by javac as an annotation processor.
func PluginFactory() android.Module {
module := &Plugin{}
@@ -32,9 +34,13 @@ func PluginFactory() android.Module {
module.AddProperties(&module.pluginProperties)
InitJavaModule(module, android.HostSupported)
+
+ android.InitBazelModule(module)
+
return module
}
+// Plugin describes a java_plugin module, a host java library that will be used by javac as an annotation processor.
type Plugin struct {
Library
@@ -50,3 +56,34 @@ type PluginProperties struct {
// parallelism and cause more recompilation for modules that depend on modules that use this plugin.
Generates_api *bool
}
+
+type pluginAttributes struct {
+ *javaCommonAttributes
+ Deps bazel.LabelListAttribute
+ Processor_class *string
+}
+
+// ConvertWithBp2build is used to convert android_app to Bazel.
+func (p *Plugin) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ pluginName := p.Name()
+ commonAttrs, depLabels := p.convertLibraryAttrsBp2Build(ctx)
+
+ deps := depLabels.Deps
+ deps.Append(depLabels.StaticDeps)
+
+ var processorClass *string
+ if p.pluginProperties.Processor_class != nil {
+ processorClass = p.pluginProperties.Processor_class
+ }
+
+ attrs := &pluginAttributes{
+ javaCommonAttributes: commonAttrs,
+ Deps: deps,
+ Processor_class: processorClass,
+ }
+
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "java_plugin",
+ }
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: pluginName}, attrs)
+}
diff --git a/java/plugin_test.go b/java/plugin_test.go
index c7913d3db..dc29b1c3e 100644
--- a/java/plugin_test.go
+++ b/java/plugin_test.go
@@ -15,7 +15,6 @@
package java
import (
- "android/soong/android"
"testing"
)
@@ -58,7 +57,7 @@ func TestPlugin(t *testing.T) {
}
`)
- buildOS := android.BuildOs.String()
+ buildOS := ctx.Config().BuildOS.String()
javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
turbine := ctx.ModuleForTests("foo", "android_common").MaybeRule("turbine")
@@ -98,7 +97,7 @@ func TestPluginGeneratesApi(t *testing.T) {
}
`)
- buildOS := android.BuildOs.String()
+ buildOS := ctx.Config().BuildOS.String()
javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
turbine := ctx.ModuleForTests("foo", "android_common").MaybeRule("turbine")
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index c33e6c229..44650a6d0 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -16,6 +16,7 @@ package java
import (
"fmt"
+ "path"
"strconv"
"strings"
@@ -37,6 +38,11 @@ type prebuiltApisProperties struct {
// list of api version directories
Api_dirs []string
+ // Directory containing finalized api txt files for extension versions.
+ // Extension versions higher than the base sdk extension version will
+ // be assumed to be finalized later than all Api_dirs.
+ Extensions_dir *string
+
// The next API directory can optionally point to a directory where
// files incompatibility-tracking files are stored for the current
// "in progress" API. Each module present in one of the api_dirs will have
@@ -60,36 +66,45 @@ func (module *prebuiltApis) GenerateAndroidBuildActions(ctx android.ModuleContex
// no need to implement
}
-func parseJarPath(path string) (module string, apiver string, scope string) {
- elements := strings.Split(path, "/")
-
- apiver = elements[0]
- scope = elements[1]
+// parsePrebuiltPath parses the relevant variables out of a variety of paths, e.g.
+// <version>/<scope>/<module>.jar
+// <version>/<scope>/api/<module>.txt
+// extensions/<version>/<scope>/<module>.jar
+// extensions/<version>/<scope>/api/<module>.txt
+func parsePrebuiltPath(ctx android.LoadHookContext, p string) (module string, version string, scope string) {
+ elements := strings.Split(p, "/")
+
+ scopeIdx := len(elements) - 2
+ if elements[scopeIdx] == "api" {
+ scopeIdx--
+ }
+ scope = elements[scopeIdx]
+ if scope != "core" && scope != "public" && scope != "system" && scope != "test" && scope != "module-lib" && scope != "system-server" {
+ ctx.ModuleErrorf("invalid scope %q found in path: %q", scope, p)
+ return
+ }
+ version = elements[scopeIdx-1]
- module = strings.TrimSuffix(elements[2], ".jar")
+ module = strings.TrimSuffix(path.Base(p), path.Ext(p))
return
}
-func parseApiFilePath(ctx android.LoadHookContext, path string) (module string, apiver string, scope string) {
- elements := strings.Split(path, "/")
- apiver = elements[0]
-
- scope = elements[1]
- if scope != "public" && scope != "system" && scope != "test" && scope != "module-lib" && scope != "system-server" {
- ctx.ModuleErrorf("invalid scope %q found in path: %q", scope, path)
+// parseFinalizedPrebuiltPath is like parsePrebuiltPath, but verifies the version is numeric (a finalized version).
+func parseFinalizedPrebuiltPath(ctx android.LoadHookContext, p string) (module string, version int, scope string) {
+ module, v, scope := parsePrebuiltPath(ctx, p)
+ version, err := strconv.Atoi(v)
+ if err != nil {
+ ctx.ModuleErrorf("Found finalized API files in non-numeric dir '%v'", v)
return
}
-
- // elements[2] is string literal "api". skipping.
- module = strings.TrimSuffix(elements[3], ".txt")
return
}
-func prebuiltApiModuleName(mctx android.LoadHookContext, module string, scope string, apiver string) string {
- return mctx.ModuleName() + "_" + scope + "_" + apiver + "_" + module
+func prebuiltApiModuleName(mctx android.LoadHookContext, module, scope, version string) string {
+ return fmt.Sprintf("%s_%s_%s_%s", mctx.ModuleName(), scope, version, module)
}
-func createImport(mctx android.LoadHookContext, module, scope, apiver, path, sdkVersion string, compileDex bool) {
+func createImport(mctx android.LoadHookContext, module, scope, version, path, sdkVersion string, compileDex bool) {
props := struct {
Name *string
Jars []string
@@ -97,7 +112,7 @@ func createImport(mctx android.LoadHookContext, module, scope, apiver, path, sdk
Installable *bool
Compile_dex *bool
}{}
- props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, apiver))
+ props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, version))
props.Jars = append(props.Jars, path)
props.Sdk_version = proptools.StringPtr(sdkVersion)
props.Installable = proptools.BoolPtr(false)
@@ -132,117 +147,125 @@ func createEmptyFile(mctx android.LoadHookContext, name string) {
mctx.CreateModule(genrule.GenRuleFactory, &props)
}
-func getPrebuiltFiles(mctx android.LoadHookContext, p *prebuiltApis, name string) []string {
+// globApiDirs collects all the files in all api_dirs and all scopes that match the given glob, e.g. '*.jar' or 'api/*.txt'.
+// <api-dir>/<scope>/<glob> for all api-dir and scope.
+func globApiDirs(mctx android.LoadHookContext, p *prebuiltApis, api_dir_glob string) []string {
var files []string
for _, apiver := range p.properties.Api_dirs {
- files = append(files, getPrebuiltFilesInSubdir(mctx, apiver, name)...)
+ files = append(files, globScopeDir(mctx, apiver, api_dir_glob)...)
}
return files
}
-func getPrebuiltFilesInSubdir(mctx android.LoadHookContext, subdir string, name string) []string {
+// globExtensionDirs collects all the files under the extension dir (for all versions and scopes) that match the given glob
+// <extension-dir>/<version>/<scope>/<glob> for all version and scope.
+func globExtensionDirs(mctx android.LoadHookContext, p *prebuiltApis, extension_dir_glob string) []string {
+ // <extensions-dir>/<num>/<extension-dir-glob>
+ return globScopeDir(mctx, *p.properties.Extensions_dir+"/*", extension_dir_glob)
+}
+
+// globScopeDir collects all the files in the given subdir across all scopes that match the given glob, e.g. '*.jar' or 'api/*.txt'.
+// <subdir>/<scope>/<glob> for all scope.
+func globScopeDir(mctx android.LoadHookContext, subdir string, subdir_glob string) []string {
var files []string
dir := mctx.ModuleDir() + "/" + subdir
for _, scope := range []string{"public", "system", "test", "core", "module-lib", "system-server"} {
- glob := fmt.Sprintf("%s/%s/%s", dir, scope, name)
+ glob := fmt.Sprintf("%s/%s/%s", dir, scope, subdir_glob)
vfiles, err := mctx.GlobWithDeps(glob, nil)
if err != nil {
- mctx.ModuleErrorf("failed to glob %s files under %q: %s", name, dir+"/"+scope, err)
+ mctx.ModuleErrorf("failed to glob %s files under %q: %s", subdir_glob, dir+"/"+scope, err)
}
files = append(files, vfiles...)
}
+ for i, f := range files {
+ files[i] = strings.TrimPrefix(f, mctx.ModuleDir()+"/")
+ }
return files
}
func prebuiltSdkStubs(mctx android.LoadHookContext, p *prebuiltApis) {
- mydir := mctx.ModuleDir() + "/"
// <apiver>/<scope>/<module>.jar
- files := getPrebuiltFiles(mctx, p, "*.jar")
+ files := globApiDirs(mctx, p, "*.jar")
sdkVersion := proptools.StringDefault(p.properties.Imports_sdk_version, "current")
compileDex := proptools.BoolDefault(p.properties.Imports_compile_dex, false)
for _, f := range files {
// create a Import module for each jar file
- localPath := strings.TrimPrefix(f, mydir)
- module, apiver, scope := parseJarPath(localPath)
- createImport(mctx, module, scope, apiver, localPath, sdkVersion, compileDex)
+ module, version, scope := parsePrebuiltPath(mctx, f)
+ createImport(mctx, module, scope, version, f, sdkVersion, compileDex)
+
+ if module == "core-for-system-modules" {
+ createSystemModules(mctx, version, scope)
+ }
}
}
-func createSystemModules(mctx android.LoadHookContext, apiver string) {
+func createSystemModules(mctx android.LoadHookContext, version, scope string) {
props := struct {
Name *string
Libs []string
}{}
- props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, "system_modules", "public", apiver))
- props.Libs = append(props.Libs, prebuiltApiModuleName(mctx, "core-for-system-modules", "public", apiver))
+ props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, "system_modules", scope, version))
+ props.Libs = append(props.Libs, prebuiltApiModuleName(mctx, "core-for-system-modules", scope, version))
mctx.CreateModule(systemModulesImportFactory, &props)
}
-func prebuiltSdkSystemModules(mctx android.LoadHookContext, p *prebuiltApis) {
- for _, apiver := range p.properties.Api_dirs {
- jar := android.ExistentPathForSource(mctx,
- mctx.ModuleDir(), apiver, "public", "core-for-system-modules.jar")
- if jar.Valid() {
- createSystemModules(mctx, apiver)
- }
- }
-}
-
func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) {
- mydir := mctx.ModuleDir() + "/"
// <apiver>/<scope>/api/<module>.txt
- files := getPrebuiltFiles(mctx, p, "api/*.txt")
-
- if len(files) == 0 {
- mctx.ModuleErrorf("no api file found under %q", mydir)
- }
-
- // construct a map to find out the latest api file path
- // for each (<module>, <scope>) pair.
- type latestApiInfo struct {
- module string
- scope string
- version int
- path string
+ apiLevelFiles := globApiDirs(mctx, p, "api/*.txt")
+ if len(apiLevelFiles) == 0 {
+ mctx.ModuleErrorf("no api file found under %q", mctx.ModuleDir())
}
// Create modules for all (<module>, <scope, <version>) triplets,
- // and a "latest" module variant for each (<module>, <scope>) pair
apiModuleName := func(module, scope, version string) string {
return module + ".api." + scope + "." + version
}
- m := make(map[string]latestApiInfo)
- for _, f := range files {
- localPath := strings.TrimPrefix(f, mydir)
- module, apiver, scope := parseApiFilePath(mctx, localPath)
- createApiModule(mctx, apiModuleName(module, scope, apiver), localPath)
+ for _, f := range apiLevelFiles {
+ module, version, scope := parseFinalizedPrebuiltPath(mctx, f)
+ createApiModule(mctx, apiModuleName(module, scope, strconv.Itoa(version)), f)
+ }
- version, err := strconv.Atoi(apiver)
- if err != nil {
- mctx.ModuleErrorf("Found finalized API files in non-numeric dir %v", apiver)
- return
- }
+ // Figure out the latest version of each module/scope
+ type latestApiInfo struct {
+ module, scope, path string
+ version int
+ }
- // Track latest version of each module/scope, except for incompatibilities
- if !strings.HasSuffix(module, "incompatibilities") {
+ getLatest := func(files []string) map[string]latestApiInfo {
+ m := make(map[string]latestApiInfo)
+ for _, f := range files {
+ module, version, scope := parseFinalizedPrebuiltPath(mctx, f)
+ if strings.HasSuffix(module, "incompatibilities") {
+ continue
+ }
key := module + "." + scope
- info, ok := m[key]
- if !ok {
- m[key] = latestApiInfo{module, scope, version, localPath}
- } else if version > info.version {
- info.version = version
- info.path = localPath
- m[key] = info
+ info, exists := m[key]
+ if !exists || version > info.version {
+ m[key] = latestApiInfo{module, scope, f, version}
+ }
+ }
+ return m
+ }
+
+ latest := getLatest(apiLevelFiles)
+ if p.properties.Extensions_dir != nil {
+ extensionApiFiles := globExtensionDirs(mctx, p, "api/*.txt")
+ for k, v := range getLatest(extensionApiFiles) {
+ if v.version > mctx.Config().PlatformBaseSdkExtensionVersion() {
+ if _, exists := latest[k]; !exists {
+ mctx.ModuleErrorf("Module %v finalized for extension %d but never during an API level; likely error", v.module, v.version)
+ }
+ latest[k] = v
}
}
}
// Sort the keys in order to make build.ninja stable
- for _, k := range android.SortedStringKeys(m) {
- info := m[k]
+ for _, k := range android.SortedStringKeys(latest) {
+ info := latest[k]
name := apiModuleName(info.module, info.scope, "latest")
createApiModule(mctx, name, info.path)
}
@@ -250,21 +273,20 @@ func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) {
// Create incompatibilities tracking files for all modules, if we have a "next" api.
incompatibilities := make(map[string]bool)
if nextApiDir := String(p.properties.Next_api_dir); nextApiDir != "" {
- files := getPrebuiltFilesInSubdir(mctx, nextApiDir, "api/*incompatibilities.txt")
+ files := globScopeDir(mctx, nextApiDir, "api/*incompatibilities.txt")
for _, f := range files {
- localPath := strings.TrimPrefix(f, mydir)
- filename, _, scope := parseApiFilePath(mctx, localPath)
+ filename, _, scope := parsePrebuiltPath(mctx, f)
referencedModule := strings.TrimSuffix(filename, "-incompatibilities")
- createApiModule(mctx, apiModuleName(referencedModule+"-incompatibilities", scope, "latest"), localPath)
+ createApiModule(mctx, apiModuleName(referencedModule+"-incompatibilities", scope, "latest"), f)
incompatibilities[referencedModule+"."+scope] = true
}
}
// Create empty incompatibilities files for remaining modules
- for _, k := range android.SortedStringKeys(m) {
+ for _, k := range android.SortedStringKeys(latest) {
if _, ok := incompatibilities[k]; !ok {
- createEmptyFile(mctx, apiModuleName(m[k].module+"-incompatibilities", m[k].scope, "latest"))
+ createEmptyFile(mctx, apiModuleName(latest[k].module+"-incompatibilities", latest[k].scope, "latest"))
}
}
}
@@ -273,7 +295,6 @@ func createPrebuiltApiModules(mctx android.LoadHookContext) {
if p, ok := mctx.Module().(*prebuiltApis); ok {
prebuiltApiFiles(mctx, p)
prebuiltSdkStubs(mctx, p)
- prebuiltSdkSystemModules(mctx, p)
}
}
diff --git a/java/prebuilt_apis_test.go b/java/prebuilt_apis_test.go
new file mode 100644
index 000000000..75422ad45
--- /dev/null
+++ b/java/prebuilt_apis_test.go
@@ -0,0 +1,92 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "sort"
+ "strings"
+ "testing"
+
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+)
+
+func intPtr(v int) *int {
+ return &v
+}
+
+func TestPrebuiltApis_SystemModulesCreation(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ FixtureWithPrebuiltApis(map[string][]string{
+ "31": {},
+ "32": {},
+ "current": {},
+ }),
+ ).RunTest(t)
+
+ sdkSystemModules := []string{}
+ result.VisitAllModules(func(module blueprint.Module) {
+ name := android.RemoveOptionalPrebuiltPrefix(module.Name())
+ if strings.HasPrefix(name, "sdk_") && strings.HasSuffix(name, "_system_modules") {
+ sdkSystemModules = append(sdkSystemModules, name)
+ }
+ })
+ sort.Strings(sdkSystemModules)
+ expected := []string{
+ // 31 only has public system modules.
+ "sdk_public_31_system_modules",
+
+ // 32 and current both have public and module-lib system modules.
+ "sdk_public_32_system_modules",
+ "sdk_module-lib_32_system_modules",
+ "sdk_public_current_system_modules",
+ "sdk_module-lib_current_system_modules",
+ }
+ sort.Strings(expected)
+ android.AssertArrayString(t, "sdk system modules", expected, sdkSystemModules)
+}
+
+func TestPrebuiltApis_WithExtensions(t *testing.T) {
+ runTestWithBaseExtensionLevel := func(v int) (foo_input string, bar_input string) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Platform_base_sdk_extension_version = intPtr(v)
+ }),
+ FixtureWithPrebuiltApisAndExtensions(map[string][]string{
+ "31": {"foo"},
+ "32": {"foo", "bar"},
+ "current": {"foo", "bar"},
+ }, map[string][]string{
+ "1": {"foo"},
+ "2": {"foo", "bar"},
+ }),
+ ).RunTest(t)
+ foo_input = result.ModuleForTests("foo.api.public.latest", "").Rule("generator").Implicits[0].String()
+ bar_input = result.ModuleForTests("bar.api.public.latest", "").Rule("generator").Implicits[0].String()
+ return
+ }
+ // Here, the base extension level is 1, so extension level 2 is the latest
+ foo_input, bar_input := runTestWithBaseExtensionLevel(1)
+ android.AssertStringEquals(t, "Expected latest = extension level 2", "prebuilts/sdk/extensions/2/public/api/foo.txt", foo_input)
+ android.AssertStringEquals(t, "Expected latest = extension level 2", "prebuilts/sdk/extensions/2/public/api/bar.txt", bar_input)
+
+ // Here, the base extension level is 2, so 2 is not later than 32.
+ foo_input, bar_input = runTestWithBaseExtensionLevel(2)
+ android.AssertStringEquals(t, "Expected latest = api level 32", "prebuilts/sdk/32/public/api/foo.txt", foo_input)
+ android.AssertStringEquals(t, "Expected latest = api level 32", "prebuilts/sdk/32/public/api/bar.txt", bar_input)
+}
diff --git a/java/proto.go b/java/proto.go
index 8731822c3..5ba486fd6 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -19,12 +19,19 @@ import (
"strconv"
"android/soong/android"
+ "android/soong/bazel"
+
+ "github.com/google/blueprint/proptools"
+)
+
+const (
+ protoTypeDefault = "lite"
)
func genProto(ctx android.ModuleContext, protoFiles android.Paths, flags android.ProtoFlags) android.Paths {
// Shard proto files into groups of 100 to avoid having to recompile all of them if one changes and to avoid
// hitting command line length limits.
- shards := android.ShardPaths(protoFiles, 100)
+ shards := android.ShardPaths(protoFiles, 50)
srcJarFiles := make(android.Paths, 0, len(shards))
@@ -73,13 +80,15 @@ func genProto(ctx android.ModuleContext, protoFiles android.Paths, flags android
}
func protoDeps(ctx android.BottomUpMutatorContext, p *android.ProtoProperties) {
+ const unspecifiedProtobufPluginType = ""
if String(p.Proto.Plugin) == "" {
switch String(p.Proto.Type) {
+ case "stream": // does not require additional dependencies
case "micro":
ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-micro")
case "nano":
ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-nano")
- case "lite", "":
+ case "lite", unspecifiedProtobufPluginType:
ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-lite")
case "full":
if ctx.Host() || ctx.BazelConversionMode() {
@@ -102,6 +111,9 @@ func protoFlags(ctx android.ModuleContext, j *CommonProperties, p *android.Proto
if String(p.Proto.Plugin) == "" {
var typeToPlugin string
switch String(p.Proto.Type) {
+ case "stream":
+ flags.proto.OutTypeFlag = "--javastream_out"
+ typeToPlugin = "javastream"
case "micro":
flags.proto.OutTypeFlag = "--javamicro_out"
typeToPlugin = "javamicro"
@@ -129,3 +141,52 @@ func protoFlags(ctx android.ModuleContext, j *CommonProperties, p *android.Proto
return flags
}
+
+type protoAttributes struct {
+ Deps bazel.LabelListAttribute
+}
+
+func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute) *bazel.Label {
+ protoInfo, ok := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, protoSrcs)
+ if !ok {
+ return nil
+ }
+
+ typ := proptools.StringDefault(protoInfo.Type, protoTypeDefault)
+ var rule_class string
+ suffix := "_java_proto"
+ switch typ {
+ case "nano":
+ suffix += "_nano"
+ rule_class = "java_nano_proto_library"
+ case "micro":
+ suffix += "_micro"
+ rule_class = "java_micro_proto_library"
+ case "lite":
+ suffix += "_lite"
+ rule_class = "java_lite_proto_library"
+ case "stream":
+ suffix += "_stream"
+ rule_class = "java_stream_proto_library"
+ case "full":
+ rule_class = "java_proto_library"
+ default:
+ ctx.PropertyErrorf("proto.type", "cannot handle conversion at this time: %q", typ)
+ }
+
+ protoLabel := bazel.Label{Label: ":" + m.Name() + "_proto"}
+ var protoAttrs protoAttributes
+ protoAttrs.Deps.SetValue(bazel.LabelList{Includes: []bazel.Label{protoLabel}})
+
+ name := m.Name() + suffix
+
+ ctx.CreateBazelTargetModule(
+ bazel.BazelTargetModuleProperties{
+ Rule_class: rule_class,
+ Bzl_load_location: "//build/bazel/rules/java:proto.bzl",
+ },
+ android.CommonAttributes{Name: name},
+ &protoAttrs)
+
+ return &bazel.Label{Label: ":" + name}
+}
diff --git a/java/proto_test.go b/java/proto_test.go
new file mode 100644
index 000000000..d1cb71448
--- /dev/null
+++ b/java/proto_test.go
@@ -0,0 +1,53 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "strings"
+ "testing"
+
+ "android/soong/android"
+)
+
+const protoModules = `
+java_library_static {
+ name: "libprotobuf-java-lite",
+}
+`
+
+func TestProtoStream(t *testing.T) {
+ bp := `
+ java_library {
+ name: "java-stream-protos",
+ proto: {
+ type: "stream",
+ },
+ srcs: [
+ "a.proto",
+ "b.proto",
+ ],
+ }
+ `
+
+ ctx := android.GroupFixturePreparers(
+ PrepareForIntegrationTestWithJava,
+ ).RunTestWithBp(t, protoModules+bp)
+
+ proto0 := ctx.ModuleForTests("java-stream-protos", "android_common").Output("proto/proto0.srcjar")
+
+ if cmd := proto0.RuleParams.Command; !strings.Contains(cmd, "--javastream_out=") {
+ t.Errorf("expected '--javastream_out' in %q", cmd)
+ }
+}
diff --git a/java/robolectric.go b/java/robolectric.go
index 9fe1f0e0f..f71952172 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -83,6 +83,9 @@ type robolectricTest struct {
testConfig android.Path
data android.Paths
+
+ forceOSType android.OsType
+ forceArchType android.ArchType
}
func (r *robolectricTest) TestSuites() []string {
@@ -115,6 +118,9 @@ func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) {
}
func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ r.forceOSType = ctx.Config().BuildOS
+ r.forceArchType = ctx.Config().BuildArch
+
r.testConfig = tradefed.AutoGenRobolectricTestConfig(ctx, r.testProperties.Test_config,
r.testProperties.Test_config_template, r.testProperties.Test_suites,
r.testProperties.Auto_gen_config)
@@ -179,7 +185,7 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext)
continue
} else if strings.HasSuffix(s, "/BaseRobolectricTest.java") {
continue
- } else if strings.HasPrefix(s, "src/") {
+ } else {
s = strings.TrimPrefix(s, "src/")
}
r.tests = append(r.tests, s)
@@ -206,7 +212,7 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext)
installDeps = append(installDeps, installedData)
}
- ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...)
+ r.installFile = ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...)
}
func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath,
@@ -270,6 +276,10 @@ func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFi
func (r *robolectricTest) AndroidMkEntries() []android.AndroidMkEntries {
entriesList := r.Library.AndroidMkEntries()
entries := &entriesList[0]
+ entries.ExtraEntries = append(entries.ExtraEntries,
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+ })
entries.ExtraFooters = []android.AndroidMkExtraFootersFunc{
func(w io.Writer, name, prefix, moduleDir string) {
@@ -342,10 +352,9 @@ func RobolectricTestFactory() android.Module {
return module
}
-func (r *robolectricTest) InstallBypassMake() bool { return true }
func (r *robolectricTest) InstallInTestcases() bool { return true }
func (r *robolectricTest) InstallForceOS() (*android.OsType, *android.ArchType) {
- return &android.BuildOs, &android.BuildArch
+ return &r.forceOSType, &r.forceArchType
}
func robolectricRuntimesFactory() android.Module {
@@ -366,6 +375,9 @@ type robolectricRuntimes struct {
props robolectricRuntimesProperties
runtimes []android.InstallPath
+
+ forceOSType android.OsType
+ forceArchType android.ArchType
}
func (r *robolectricRuntimes) TestSuites() []string {
@@ -385,6 +397,9 @@ func (r *robolectricRuntimes) GenerateAndroidBuildActions(ctx android.ModuleCont
return
}
+ r.forceOSType = ctx.Config().BuildOS
+ r.forceArchType = ctx.Config().BuildArch
+
files := android.PathsForModuleSrc(ctx, r.props.Jars)
androidAllDir := android.PathForModuleInstall(ctx, "android-all")
@@ -405,15 +420,16 @@ func (r *robolectricRuntimes) GenerateAndroidBuildActions(ctx android.ModuleCont
}
runtimeFromSourceJar := android.OutputFileForModule(ctx, runtimeFromSourceModule, "")
- runtimeName := fmt.Sprintf("android-all-%s-robolectric-r0.jar",
- ctx.Config().PlatformSdkCodename())
+ // "TREE" name is essential here because it hooks into the "TREE" name in
+ // Robolectric's SdkConfig.java that will always correspond to the NEWEST_SDK
+ // in Robolectric configs.
+ runtimeName := "android-all-current-robolectric-r0.jar"
installedRuntime := ctx.InstallFile(androidAllDir, runtimeName, runtimeFromSourceJar)
r.runtimes = append(r.runtimes, installedRuntime)
}
}
-func (r *robolectricRuntimes) InstallBypassMake() bool { return true }
func (r *robolectricRuntimes) InstallInTestcases() bool { return true }
func (r *robolectricRuntimes) InstallForceOS() (*android.OsType, *android.ArchType) {
- return &android.BuildOs, &android.BuildArch
+ return &r.forceOSType, &r.forceArchType
}
diff --git a/java/rro.go b/java/rro.go
index 2e58c042f..c98cbbd2d 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -51,6 +51,9 @@ type RuntimeResourceOverlayProperties struct {
// Name of the signing certificate lineage file.
Lineage *string
+ // For overriding the --rotation-min-sdk-version property of apksig
+ RotationMinSdkVersion *string
+
// optional theme name. If specified, the overlay package will be applied
// only when the ro.boot.vendor.overlay.theme system property is set to the same value.
Theme *string
@@ -90,6 +93,22 @@ type RuntimeResourceOverlayModule interface {
Theme() string
}
+// RRO's partition logic is different from the partition logic of other modules defined in soong/android/paths.go
+// The default partition for RRO is "/product" and not "/system"
+func rroPartition(ctx android.ModuleContext) string {
+ var partition string
+ if ctx.DeviceSpecific() {
+ partition = ctx.DeviceConfig().OdmPath()
+ } else if ctx.SocSpecific() {
+ partition = ctx.DeviceConfig().VendorPath()
+ } else if ctx.SystemExtSpecific() {
+ partition = ctx.DeviceConfig().SystemExtPath()
+ } else {
+ partition = ctx.DeviceConfig().ProductPath()
+ }
+ return partition
+}
+
func (r *RuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) {
sdkDep := decodeSdkDep(ctx, android.SdkContext(r))
if sdkDep.hasFrameworkLibs() {
@@ -123,7 +142,7 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC
aaptLinkFlags = append(aaptLinkFlags,
"--rename-overlay-target-package "+*r.overridableProperties.Target_package_name)
}
- r.aapt.buildActions(ctx, r, nil, aaptLinkFlags...)
+ r.aapt.buildActions(ctx, r, nil, nil, aaptLinkFlags...)
// Sign the built package
_, certificates := collectAppDeps(ctx, r, false, false)
@@ -133,11 +152,15 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC
if lineage := String(r.properties.Lineage); lineage != "" {
lineageFile = android.PathForModuleSrc(ctx, lineage)
}
- SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, lineageFile)
+
+ rotationMinSdkVersion := String(r.properties.RotationMinSdkVersion)
+
+ SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, lineageFile, rotationMinSdkVersion)
r.certificate = certificates[0]
r.outputFile = signed
- r.installDir = android.PathForModuleInstall(ctx, "overlay", String(r.properties.Theme))
+ partition := rroPartition(ctx)
+ r.installDir = android.PathForModuleInPartitionInstall(ctx, partition, "overlay", String(r.properties.Theme))
ctx.InstallFile(r.installDir, r.outputFile.Base(), r.outputFile)
}
diff --git a/java/rro_test.go b/java/rro_test.go
index bad60bc16..00ba5ba11 100644
--- a/java/rro_test.go
+++ b/java/rro_test.go
@@ -33,6 +33,7 @@ func TestRuntimeResourceOverlay(t *testing.T) {
name: "foo",
certificate: "platform",
lineage: "lineage.bin",
+ rotationMinSdkVersion: "32",
product_specific: true,
static_libs: ["bar"],
resource_libs: ["baz"],
@@ -62,6 +63,7 @@ func TestRuntimeResourceOverlay(t *testing.T) {
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
PrepareForTestWithOverlayBuildComponents,
+ android.FixtureModifyConfig(android.SetKatiEnabledForTests),
fs.AddToFixture(),
).RunTestWithBp(t, bp)
@@ -88,13 +90,14 @@ func TestRuntimeResourceOverlay(t *testing.T) {
t.Errorf("Resource lib flag %q missing in aapt2 link flags: %q", resourceLibFlag, aapt2Flags)
}
- // Check cert signing flag.
+ // Check cert signing flags.
signedApk := m.Output("signed/foo.apk")
- lineageFlag := signedApk.Args["flags"]
- expectedLineageFlag := "--lineage lineage.bin"
- if expectedLineageFlag != lineageFlag {
- t.Errorf("Incorrect signing lineage flags, expected: %q, got: %q", expectedLineageFlag, lineageFlag)
+ actualCertSigningFlags := signedApk.Args["flags"]
+ expectedCertSigningFlags := "--lineage lineage.bin --rotation-min-sdk-version 32"
+ if expectedCertSigningFlags != actualCertSigningFlags {
+ t.Errorf("Incorrect cert signing flags, expected: %q, got: %q", expectedCertSigningFlags, actualCertSigningFlags)
}
+
signingFlag := signedApk.Args["certificates"]
expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8"
if expected != signingFlag {
@@ -127,7 +130,10 @@ func TestRuntimeResourceOverlay(t *testing.T) {
}
func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) {
- ctx, config := testJava(t, `
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.FixtureModifyConfig(android.SetKatiEnabledForTests),
+ ).RunTestWithBp(t, `
java_defaults {
name: "rro_defaults",
theme: "default_theme",
@@ -148,7 +154,7 @@ func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) {
//
// RRO module with defaults
//
- m := ctx.ModuleForTests("foo_with_defaults", "android_common")
+ m := result.ModuleForTests("foo_with_defaults", "android_common")
// Check AAPT2 link flags.
aapt2Flags := strings.Split(m.Output("package-res.apk").Args["flags"], " ")
@@ -159,14 +165,14 @@ func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) {
}
// Check device location.
- path := android.AndroidMkEntriesForTest(t, ctx, m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
+ path := android.AndroidMkEntriesForTest(t, result.TestContext, m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
expectedPath := []string{shared.JoinPath("out/target/product/test_device/product/overlay/default_theme")}
- android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_MODULE_PATH", config, expectedPath, path)
+ android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_MODULE_PATH", result.Config, expectedPath, path)
//
// RRO module without defaults
//
- m = ctx.ModuleForTests("foo_barebones", "android_common")
+ m = result.ModuleForTests("foo_barebones", "android_common")
// Check AAPT2 link flags.
aapt2Flags = strings.Split(m.Output("package-res.apk").Args["flags"], " ")
@@ -176,9 +182,9 @@ func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) {
}
// Check device location.
- path = android.AndroidMkEntriesForTest(t, ctx, m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
- expectedPath = []string{shared.JoinPath("out/target/product/test_device/system/overlay")}
- android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_MODULE_PATH", config, expectedPath, path)
+ path = android.AndroidMkEntriesForTest(t, result.TestContext, m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
+ expectedPath = []string{shared.JoinPath("out/target/product/test_device/product/overlay")}
+ android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_MODULE_PATH", result.Config, expectedPath, path)
}
func TestOverrideRuntimeResourceOverlay(t *testing.T) {
@@ -343,3 +349,57 @@ func TestEnforceRRO_propagatesToDependencies(t *testing.T) {
})
}
}
+
+func TestRuntimeResourceOverlayPartition(t *testing.T) {
+ bp := `
+ runtime_resource_overlay {
+ name: "device_specific",
+ device_specific: true,
+ }
+ runtime_resource_overlay {
+ name: "soc_specific",
+ soc_specific: true,
+ }
+ runtime_resource_overlay {
+ name: "system_ext_specific",
+ system_ext_specific: true,
+ }
+ runtime_resource_overlay {
+ name: "product_specific",
+ product_specific: true,
+ }
+ runtime_resource_overlay {
+ name: "default"
+ }
+ `
+ testCases := []struct {
+ name string
+ expectedPath string
+ }{
+ {
+ name: "device_specific",
+ expectedPath: "out/soong/target/product/test_device/odm/overlay",
+ },
+ {
+ name: "soc_specific",
+ expectedPath: "out/soong/target/product/test_device/vendor/overlay",
+ },
+ {
+ name: "system_ext_specific",
+ expectedPath: "out/soong/target/product/test_device/system_ext/overlay",
+ },
+ {
+ name: "product_specific",
+ expectedPath: "out/soong/target/product/test_device/product/overlay",
+ },
+ {
+ name: "default",
+ expectedPath: "out/soong/target/product/test_device/product/overlay",
+ },
+ }
+ for _, testCase := range testCases {
+ ctx, _ := testJava(t, bp)
+ mod := ctx.ModuleForTests(testCase.name, "android_common").Module().(*RuntimeResourceOverlay)
+ android.AssertPathRelativeToTopEquals(t, "Install dir is not correct for "+testCase.name, testCase.expectedPath, mod.installDir)
+ }
+}
diff --git a/java/sdk.go b/java/sdk.go
index d1b899e48..0dddd40aa 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -55,9 +55,35 @@ func defaultJavaLanguageVersion(ctx android.EarlyModuleContext, s android.SdkSpe
return JAVA_VERSION_7
} else if sdk.FinalOrFutureInt() <= 29 {
return JAVA_VERSION_8
- } else {
+ } else if sdk.FinalOrFutureInt() <= 31 {
return JAVA_VERSION_9
+ } else {
+ return JAVA_VERSION_11
+ }
+}
+
+// systemModuleKind returns the kind of system modules to use for the supplied combination of sdk
+// kind and API level.
+func systemModuleKind(sdkKind android.SdkKind, apiLevel android.ApiLevel) android.SdkKind {
+ systemModuleKind := sdkKind
+ if apiLevel.LessThanOrEqualTo(android.LastWithoutModuleLibCoreSystemModules) {
+ // API levels less than or equal to 31 did not provide a core-for-system-modules.jar
+ // specifically for the module-lib API. So, always use the public system modules for them.
+ systemModuleKind = android.SdkPublic
+ } else if systemModuleKind == android.SdkCore {
+ // Core is by definition what is included in the system module for the public API so should
+ // just use its system modules.
+ systemModuleKind = android.SdkPublic
+ } else if systemModuleKind == android.SdkSystem || systemModuleKind == android.SdkTest {
+ // The core system and test APIs are currently the same as the public API so they should use
+ // its system modules.
+ systemModuleKind = android.SdkPublic
+ } else if systemModuleKind == android.SdkSystemServer {
+ // The core system server API is the same as the core module-lib API.
+ systemModuleKind = android.SdkModule
}
+
+ return systemModuleKind
}
func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext android.SdkContext) sdkDep {
@@ -105,7 +131,8 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext android.SdkContext)
var systemModules string
if defaultJavaLanguageVersion(ctx, sdkVersion).usesJavaModules() {
- systemModules = "sdk_public_" + sdkVersion.ApiLevel.String() + "_system_modules"
+ systemModuleKind := systemModuleKind(sdkVersion.Kind, sdkVersion.ApiLevel)
+ systemModules = fmt.Sprintf("sdk_%s_%s_system_modules", systemModuleKind, sdkVersion.ApiLevel)
}
return sdkDep{
@@ -116,13 +143,15 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext android.SdkContext)
}
}
- toModule := func(modules []string, res string, aidl android.Path) sdkDep {
+ toModule := func(module string, aidl android.Path) sdkDep {
+ // Select the kind of system modules needed for the sdk version.
+ systemModulesKind := systemModuleKind(sdkVersion.Kind, android.FutureApiLevel)
return sdkDep{
useModule: true,
- bootclasspath: append(modules, config.DefaultLambdaStubsLibrary),
- systemModules: "core-current-stubs-system-modules",
- java9Classpath: modules,
- frameworkResModule: res,
+ bootclasspath: []string{module, config.DefaultLambdaStubsLibrary},
+ systemModules: fmt.Sprintf("core-%s-stubs-system-modules", systemModulesKind),
+ java9Classpath: []string{module},
+ frameworkResModule: "framework-res",
aidl: android.OptionalPathForPath(aidl),
}
}
@@ -161,38 +190,24 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext android.SdkContext)
noFrameworksLibs: true,
}
case android.SdkPublic:
- return toModule([]string{"android_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
+ return toModule("android_stubs_current", sdkFrameworkAidlPath(ctx))
case android.SdkSystem:
- return toModule([]string{"android_system_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
+ return toModule("android_system_stubs_current", sdkFrameworkAidlPath(ctx))
case android.SdkTest:
- return toModule([]string{"android_test_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
+ return toModule("android_test_stubs_current", sdkFrameworkAidlPath(ctx))
case android.SdkCore:
return sdkDep{
useModule: true,
bootclasspath: []string{"core.current.stubs", config.DefaultLambdaStubsLibrary},
- systemModules: "core-current-stubs-system-modules",
+ systemModules: "core-public-stubs-system-modules",
noFrameworksLibs: true,
}
case android.SdkModule:
// TODO(146757305): provide .apk and .aidl that have more APIs for modules
- return sdkDep{
- useModule: true,
- bootclasspath: []string{"android_module_lib_stubs_current", config.DefaultLambdaStubsLibrary},
- systemModules: "core-module-lib-stubs-system-modules",
- java9Classpath: []string{"android_module_lib_stubs_current"},
- frameworkResModule: "framework-res",
- aidl: android.OptionalPathForPath(nonUpdatableFrameworkAidlPath(ctx)),
- }
+ return toModule("android_module_lib_stubs_current", nonUpdatableFrameworkAidlPath(ctx))
case android.SdkSystemServer:
// TODO(146757305): provide .apk and .aidl that have more APIs for modules
- return sdkDep{
- useModule: true,
- bootclasspath: []string{"android_system_server_stubs_current", config.DefaultLambdaStubsLibrary},
- systemModules: "core-module-lib-stubs-system-modules",
- java9Classpath: []string{"android_system_server_stubs_current"},
- frameworkResModule: "framework-res",
- aidl: android.OptionalPathForPath(sdkFrameworkAidlPath(ctx)),
- }
+ return toModule("android_system_server_stubs_current", sdkFrameworkAidlPath(ctx))
default:
panic(fmt.Errorf("invalid sdk %q", sdkVersion.Raw))
}
@@ -370,7 +385,7 @@ func createAPIFingerprint(ctx android.SingletonContext) {
"frameworks-base-api-current.txt",
"frameworks-base-api-system-current.txt",
"frameworks-base-api-module-lib-current.txt",
- "services-system-server-current.txt",
+ "frameworks-base-api-system-server-current.txt",
}
count := 0
ctx.VisitAllModules(func(module android.Module) {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 8c664383d..47ffc6afc 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -32,25 +32,7 @@ import (
)
const (
- sdkXmlFileSuffix = ".xml"
- permissionsTemplate = `<?xml version=\"1.0\" encoding=\"utf-8\"?>\n` +
- `<!-- Copyright (C) 2018 The Android Open Source Project\n` +
- `\n` +
- ` Licensed under the Apache License, Version 2.0 (the \"License\");\n` +
- ` you may not use this file except in compliance with the License.\n` +
- ` You may obtain a copy of the License at\n` +
- `\n` +
- ` http://www.apache.org/licenses/LICENSE-2.0\n` +
- `\n` +
- ` Unless required by applicable law or agreed to in writing, software\n` +
- ` distributed under the License is distributed on an \"AS IS\" BASIS,\n` +
- ` WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n` +
- ` See the License for the specific language governing permissions and\n` +
- ` limitations under the License.\n` +
- `-->\n` +
- `<permissions>\n` +
- ` <library name=\"%s\" file=\"%s\"/>\n` +
- `</permissions>\n`
+ sdkXmlFileSuffix = ".xml"
)
// A tag to associated a dependency with a specific api scope.
@@ -361,13 +343,14 @@ type ApiScopeProperties struct {
// The sdk_version to use for building the stubs.
//
// If not specified then it will use an sdk_version determined as follows:
+ //
// 1) If the sdk_version specified on the java_sdk_library is none then this
- // will be none. This is used for java_sdk_library instances that are used
- // to create stubs that contribute to the core_current sdk version.
- // 2) Otherwise, it is assumed that this library extends but does not contribute
- // directly to a specific sdk_version and so this uses the sdk_version appropriate
- // for the api scope. e.g. public will use sdk_version: current, system will use
- // sdk_version: system_current, etc.
+ // will be none. This is used for java_sdk_library instances that are used
+ // to create stubs that contribute to the core_current sdk version.
+ // 2) Otherwise, it is assumed that this library extends but does not
+ // contribute directly to a specific sdk_version and so this uses the
+ // sdk_version appropriate for the api scope. e.g. public will use
+ // sdk_version: current, system will use sdk_version: system_current, etc.
//
// This does not affect the sdk_version used for either generating the stubs source
// or the API file. They both have to use the same sdk_version as is used for
@@ -376,6 +359,9 @@ type ApiScopeProperties struct {
}
type sdkLibraryProperties struct {
+ // List of source files that are needed to compile the API, but are not part of runtime library.
+ Api_srcs []string `android:"arch_variant"`
+
// Visibility for impl library module. If not specified then defaults to the
// visibility property.
Impl_library_visibility []string
@@ -391,6 +377,9 @@ type sdkLibraryProperties struct {
// List of Java libraries that will be in the classpath when building the implementation lib
Impl_only_libs []string `android:"arch_variant"`
+ // List of Java libraries that will included in the implementation lib.
+ Impl_only_static_libs []string `android:"arch_variant"`
+
// List of Java libraries that will be in the classpath when building stubs
Stub_only_libs []string `android:"arch_variant"`
@@ -419,7 +408,7 @@ type sdkLibraryProperties struct {
// local files that are used within user customized droiddoc options.
Droiddoc_option_files []string
- // additional droiddoc options
+ // additional droiddoc options.
// Available variables for substitution:
//
// $(location <label>): the path to the droiddoc_option_files with name <label>
@@ -537,7 +526,7 @@ type scopePaths struct {
// The dex jar for the stubs.
//
// This is not the implementation jar, it still only contains stubs.
- stubsDexJarPath android.Path
+ stubsDexJarPath OptionalDexJarPath
// The API specification file, e.g. system_current.txt.
currentApiFilePath android.OptionalPath
@@ -547,6 +536,9 @@ type scopePaths struct {
// The stubs source jar.
stubsSrcJar android.OptionalPath
+
+ // Extracted annotations.
+ annotationsZip android.OptionalPath
}
func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error {
@@ -582,6 +574,7 @@ func (paths *scopePaths) treatDepAsApiStubsSrcProvider(dep android.Module, actio
}
func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider) {
+ paths.annotationsZip = android.OptionalPathForPath(provider.AnnotationsZip())
paths.currentApiFilePath = android.OptionalPathForPath(provider.ApiFilePath())
paths.removedApiFilePath = android.OptionalPathForPath(provider.RemovedApiFilePath())
}
@@ -629,6 +622,33 @@ type commonToSdkLibraryAndImportProperties struct {
// Files containing information about supported java doc tags.
Doctag_files []string `android:"path"`
+
+ // Signals that this shared library is part of the bootclasspath starting
+ // on the version indicated in this attribute.
+ //
+ // This will make platforms at this level and above to ignore
+ // <uses-library> tags with this library name because the library is already
+ // available
+ On_bootclasspath_since *string
+
+ // Signals that this shared library was part of the bootclasspath before
+ // (but not including) the version indicated in this attribute.
+ //
+ // The system will automatically add a <uses-library> tag with this library to
+ // apps that target any SDK less than the version indicated in this attribute.
+ On_bootclasspath_before *string
+
+ // Indicates that PackageManager should ignore this shared library if the
+ // platform is below the version indicated in this attribute.
+ //
+ // This means that the device won't recognise this library as installed.
+ Min_device_sdk *string
+
+ // Indicates that PackageManager should ignore this shared library if the
+ // platform is above the version indicated in this attribute.
+ //
+ // This means that the device won't recognise this library as installed.
+ Max_device_sdk *string
}
// commonSdkLibraryAndImportModule defines the interface that must be provided by a module that
@@ -736,6 +756,8 @@ const (
apiTxtComponentName = "api.txt"
removedApiTxtComponentName = "removed-api.txt"
+
+ annotationsComponentName = "annotations.zip"
)
// A regular expression to match tags that reference a specific stubs component.
@@ -754,7 +776,7 @@ var tagSplitter = func() *regexp.Regexp {
scopesRegexp := choice(allScopeNames...)
// Regular expression to match one of the components.
- componentsRegexp := choice(stubsSourceComponentName, apiTxtComponentName, removedApiTxtComponentName)
+ componentsRegexp := choice(stubsSourceComponentName, apiTxtComponentName, removedApiTxtComponentName, annotationsComponentName)
// Regular expression to match any combination of one scope and one component.
return regexp.MustCompile(fmt.Sprintf(`^\.(%s)\.(%s)$`, scopesRegexp, componentsRegexp))
@@ -762,9 +784,7 @@ var tagSplitter = func() *regexp.Regexp {
// For OutputFileProducer interface
//
-// .<scope>.stubs.source
-// .<scope>.api.txt
-// .<scope>.removed-api.txt
+// .<scope>.<component name>, for all ComponentNames (for example: .public.removed-api.txt)
func (c *commonToSdkLibraryAndImport) commonOutputFiles(tag string) (android.Paths, error) {
if groups := tagSplitter.FindStringSubmatch(tag); groups != nil {
scopeName := groups[1]
@@ -791,6 +811,11 @@ func (c *commonToSdkLibraryAndImport) commonOutputFiles(tag string) (android.Pat
if paths.removedApiFilePath.Valid() {
return android.Paths{paths.removedApiFilePath.Path()}, nil
}
+
+ case annotationsComponentName:
+ if paths.annotationsZip.Valid() {
+ return android.Paths{paths.annotationsZip.Path()}, nil
+ }
}
return nil, fmt.Errorf("%s not available for api scope %s", component, scopeName)
@@ -903,10 +928,10 @@ func sdkKindToApiScope(kind android.SdkKind) *apiScope {
}
// to satisfy SdkLibraryDependency interface
-func (c *commonToSdkLibraryAndImport) SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) android.Path {
+func (c *commonToSdkLibraryAndImport) SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath {
paths := c.selectScopePaths(ctx, kind)
if paths == nil {
- return nil
+ return makeUnsetDexJarPath()
}
return paths.stubsDexJarPath
@@ -981,13 +1006,15 @@ func (e *EmbeddableSdkLibraryComponent) SdkLibraryName() *string {
}
// to satisfy SdkLibraryComponentDependency
-func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() *string {
- return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack
-}
-
-// to satisfy SdkLibraryComponentDependency
func (e *EmbeddableSdkLibraryComponent) OptionalSdkLibraryImplementation() *string {
- // Currently implementation library name is the same as the SDK library name.
+ // For shared libraries, this is the same as the SDK library name. If a Java library or app
+ // depends on a component library (e.g. a stub library) it still needs to know the name of the
+ // run-time library and the corresponding module that provides the implementation. This name is
+ // passed to manifest_fixer (to be added to AndroidManifest.xml) and added to CLC (to be used
+ // in dexpreopt).
+ //
+ // For non-shared SDK (component or not) libraries this returns `nil`, as they are not
+ // <uses-library> and should not be added to the manifest or to CLC.
return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack
}
@@ -999,12 +1026,6 @@ type SdkLibraryComponentDependency interface {
// SdkLibraryName returns the name of the java_sdk_library/_import module.
SdkLibraryName() *string
- // The optional name of the sdk library that should be implicitly added to the
- // AndroidManifest of an app that contains code which references the sdk library.
- //
- // Returns the name of the optional implicit SDK library or nil, if there isn't one.
- OptionalImplicitSdkLibrary() *string
-
// The name of the implementation library for the optional SDK library or nil, if there isn't one.
OptionalSdkLibraryImplementation() *string
}
@@ -1036,7 +1057,7 @@ type SdkLibraryDependency interface {
// SdkApiStubDexJar returns the dex jar for the stubs. It is needed by the hiddenapi processing
// tool which processes dex files.
- SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) android.Path
+ SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath
// SdkRemovedTxtFile returns the optional path to the removed.txt file for the specified sdk kind.
SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath
@@ -1110,6 +1131,22 @@ func (module *SdkLibrary) getGeneratedApiScopes(ctx android.EarlyModuleContext)
return generatedScopes
}
+var _ android.ModuleWithMinSdkVersionCheck = (*SdkLibrary)(nil)
+
+func (module *SdkLibrary) CheckMinSdkVersion(ctx android.ModuleContext) {
+ android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx).ApiLevel, func(c android.ModuleContext, do android.PayloadDepsCallback) {
+ ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
+ isExternal := !module.depIsInSameApex(ctx, child)
+ if am, ok := child.(android.ApexModule); ok {
+ if !do(ctx, parent, am, isExternal) {
+ return false
+ }
+ }
+ return !isExternal
+ })
+ })
+}
+
type sdkLibraryComponentTag struct {
blueprint.BaseDependencyTag
name string
@@ -1187,14 +1224,23 @@ func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) {
paths, err := module.commonOutputFiles(tag)
- if paths == nil && err == nil {
- return module.Library.OutputFiles(tag)
- } else {
+ if paths != nil || err != nil {
return paths, err
}
+ if module.requiresRuntimeImplementationLibrary() {
+ return module.Library.OutputFiles(tag)
+ }
+ if tag == "" {
+ return nil, nil
+ }
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
}
func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ if proptools.String(module.deviceProperties.Min_sdk_version) != "" {
+ module.CheckMinSdkVersion(ctx)
+ }
+
module.generateCommonBuildActions(ctx)
// Only build an implementation library if required.
@@ -1303,10 +1349,12 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext)
visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility)
props := struct {
- Name *string
- Visibility []string
- Instrument bool
- Libs []string
+ Name *string
+ Visibility []string
+ Instrument bool
+ Libs []string
+ Static_libs []string
+ Apex_available []string
}{
Name: proptools.StringPtr(module.implLibraryModuleName()),
Visibility: visibility,
@@ -1315,6 +1363,12 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext)
// Set the impl_only libs. Note that the module's "Libs" get appended as well, via the
// addition of &module.properties below.
Libs: module.sdkLibraryProperties.Impl_only_libs,
+ // Set the impl_only static libs. Note that the module's "static_libs" get appended as well, via the
+ // addition of &module.properties below.
+ Static_libs: module.sdkLibraryProperties.Impl_only_static_libs,
+ // Pass the apex_available settings down so that the impl library can be statically
+ // embedded within a library that is added to an APEX. Needed for updatable-media.
+ Apex_available: module.ApexAvailable(),
}
properties := []interface{}{
@@ -1442,6 +1496,7 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC
props.Name = proptools.StringPtr(name)
props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_source_visibility)
props.Srcs = append(props.Srcs, module.properties.Srcs...)
+ props.Srcs = append(props.Srcs, module.sdkLibraryProperties.Api_srcs...)
props.Sdk_version = module.deviceProperties.Sdk_version
props.System_modules = module.deviceProperties.System_modules
props.Installable = proptools.BoolPtr(false)
@@ -1467,15 +1522,15 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC
}
droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...)
disabledWarnings := []string{
- "MissingPermission",
"BroadcastBehavior",
- "HiddenSuperclass",
"DeprecationMismatch",
- "UnavailableSymbol",
- "SdkConstant",
+ "HiddenSuperclass",
"HiddenTypeParameter",
+ "MissingPermission",
+ "SdkConstant",
"Todo",
"Typo",
+ "UnavailableSymbol",
}
droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
@@ -1570,14 +1625,29 @@ func (module *SdkLibrary) UniqueApexVariations() bool {
// Creates the xml file that publicizes the runtime library
func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) {
+ moduleMinApiLevel := module.Library.MinSdkVersion(mctx).ApiLevel
+ var moduleMinApiLevelStr = moduleMinApiLevel.String()
+ if moduleMinApiLevel == android.NoneApiLevel {
+ moduleMinApiLevelStr = "current"
+ }
props := struct {
- Name *string
- Lib_name *string
- Apex_available []string
+ Name *string
+ Lib_name *string
+ Apex_available []string
+ On_bootclasspath_since *string
+ On_bootclasspath_before *string
+ Min_device_sdk *string
+ Max_device_sdk *string
+ Sdk_library_min_api_level *string
}{
- Name: proptools.StringPtr(module.xmlPermissionsModuleName()),
- Lib_name: proptools.StringPtr(module.BaseModuleName()),
- Apex_available: module.ApexProperties.Apex_available,
+ Name: proptools.StringPtr(module.xmlPermissionsModuleName()),
+ Lib_name: proptools.StringPtr(module.BaseModuleName()),
+ Apex_available: module.ApexProperties.Apex_available,
+ On_bootclasspath_since: module.commonSdkLibraryProperties.On_bootclasspath_since,
+ On_bootclasspath_before: module.commonSdkLibraryProperties.On_bootclasspath_before,
+ Min_device_sdk: module.commonSdkLibraryProperties.Min_device_sdk,
+ Max_device_sdk: module.commonSdkLibraryProperties.Max_device_sdk,
+ Sdk_library_min_api_level: &moduleMinApiLevelStr,
}
mctx.CreateModule(sdkLibraryXmlFactory, &props)
@@ -1700,8 +1770,12 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont
path := path.Join(mctx.ModuleDir(), apiDir, scope.apiFilePrefix+api)
p := android.ExistentPathForSource(mctx, path)
if !p.Valid() {
- mctx.ModuleErrorf("Current api file %#v doesn't exist", path)
- missingCurrentApi = true
+ if mctx.Config().AllowMissingDependencies() {
+ mctx.AddMissingDependencies([]string{path})
+ } else {
+ mctx.ModuleErrorf("Current api file %#v doesn't exist", path)
+ missingCurrentApi = true
+ }
}
}
}
@@ -1751,8 +1825,9 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont
*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
}
- // Add the impl_only_libs *after* we're done using the Libs prop in submodules.
+ // Add the impl_only_libs and impl_only_static_libs *after* we're done using them in submodules.
module.properties.Libs = append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...)
+ module.properties.Static_libs = append(module.properties.Static_libs, module.sdkLibraryProperties.Impl_only_static_libs...)
}
func (module *SdkLibrary) InitSdkLibraryProperties() {
@@ -1884,6 +1959,9 @@ type sdkLibraryScopeProperties struct {
// The removed.txt
Removed_api *string `android:"path"`
+
+ // Annotation zip
+ Annotations *string `android:"path"`
}
type sdkLibraryImportProperties struct {
@@ -1895,7 +1973,6 @@ type sdkLibraryImportProperties struct {
Compile_dex *bool
// If not empty, classes are restricted to the specified packages and their sub-packages.
- // This information is used to generate the updatable-bcp-packages.txt file.
Permitted_packages []string
}
@@ -1907,6 +1984,7 @@ type SdkLibraryImport struct {
android.SdkBase
hiddenAPI
+ dexpreopter
properties sdkLibraryImportProperties
@@ -1923,8 +2001,12 @@ type SdkLibraryImport struct {
// Is nil if the source module does not exist.
xmlPermissionsFileModule *sdkLibraryXml
- // Path to the dex implementation jar obtained from the prebuilt_apex, if any.
- dexJarFile android.Path
+ // Build path to the dex implementation jar obtained from the prebuilt_apex, if any.
+ dexJarFile OptionalDexJarPath
+
+ // Expected install file path of the source module(sdk_library)
+ // or dex implementation jar obtained from the prebuilt_apex, if any.
+ installFile android.Path
}
var _ SdkLibraryDependency = (*SdkLibraryImport)(nil)
@@ -2107,6 +2189,14 @@ func (module *SdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext)
}
}
+func (module *SdkLibraryImport) AndroidMkEntries() []android.AndroidMkEntries {
+ // For an SDK library imported from a prebuilt APEX, we don't need a Make module for itself, as we
+ // don't need to install it. However, we need to add its dexpreopt outputs as sub-modules, if it
+ // is preopted.
+ dexpreoptEntries := module.dexpreopter.AndroidMkEntriesForApex()
+ return append(dexpreoptEntries, android.AndroidMkEntries{Disabled: true})
+}
+
var _ android.ApexModule = (*SdkLibraryImport)(nil)
// Implements android.ApexModule
@@ -2133,14 +2223,30 @@ func (module *SdkLibraryImport) UniqueApexVariations() bool {
return module.uniqueApexVariations()
}
+// MinSdkVersion - Implements hiddenAPIModule
+func (module *SdkLibraryImport) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecNone
+}
+
+var _ hiddenAPIModule = (*SdkLibraryImport)(nil)
+
func (module *SdkLibraryImport) OutputFiles(tag string) (android.Paths, error) {
- return module.commonOutputFiles(tag)
+ paths, err := module.commonOutputFiles(tag)
+ if paths != nil || err != nil {
+ return paths, err
+ }
+ if module.implLibraryModule != nil {
+ return module.implLibraryModule.OutputFiles(tag)
+ } else {
+ return nil, nil
+ }
}
func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
module.generateCommonBuildActions(ctx)
- var deapexerModule android.Module
+ // Assume that source module(sdk_library) is installed in /<sdk_library partition>/framework
+ module.installFile = android.PathForModuleInstall(ctx, "framework", module.Stem()+".jar")
// Record the paths to the prebuilt stubs library and stubs source.
ctx.VisitDirectDeps(func(to android.Module) {
@@ -2167,15 +2273,6 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo
ctx.ModuleErrorf("xml permissions file module must be of type *sdkLibraryXml but was %T", to)
}
}
-
- // Save away the `deapexer` module on which this depends, if any.
- if tag == android.DeapexerTag {
- if deapexerModule != nil {
- ctx.ModuleErrorf("Ambiguous duplicate deapexer module dependencies %q and %q",
- deapexerModule.Name(), to.Name())
- }
- deapexerModule = to
- }
})
// Populate the scope paths with information from the properties.
@@ -2185,6 +2282,7 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo
}
paths := module.getScopePathsCreateIfNeeded(apiScope)
+ paths.annotationsZip = android.OptionalPathForModuleSrc(ctx, scopeProperties.Annotations)
paths.currentApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Current_api)
paths.removedApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Removed_api)
}
@@ -2194,22 +2292,28 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo
// obtained from the associated deapexer module.
ai := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if ai.ForPrebuiltApex {
- if deapexerModule == nil {
- // This should never happen as a variant for a prebuilt_apex is only created if the
- // deapxer module has been configured to export the dex implementation jar for this module.
- ctx.ModuleErrorf("internal error: module %q does not depend on a `deapexer` module for prebuilt_apex %q",
- module.Name(), ai.ApexVariationName)
- }
-
// Get the path of the dex implementation jar from the `deapexer` module.
- di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo)
+ di := android.FindDeapexerProviderForModule(ctx)
+ if di == nil {
+ return // An error has been reported by FindDeapexerProviderForModule.
+ }
if dexOutputPath := di.PrebuiltExportPath(apexRootRelativePathToJavaLib(module.BaseModuleName())); dexOutputPath != nil {
- module.dexJarFile = dexOutputPath
- module.initHiddenAPI(ctx, dexOutputPath, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil)
+ dexJarFile := makeDexJarPathFromPath(dexOutputPath)
+ module.dexJarFile = dexJarFile
+ installPath := android.PathForModuleInPartitionInstall(
+ ctx, "apex", ai.ApexVariationName, apexRootRelativePathToJavaLib(module.BaseModuleName()))
+ module.installFile = installPath
+ module.initHiddenAPI(ctx, dexJarFile, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil)
+
+ // Dexpreopting.
+ module.dexpreopter.installPath = module.dexpreopter.getInstallPath(ctx, installPath)
+ module.dexpreopter.isSDKLibrary = true
+ module.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &module.dexpreopter)
+ module.dexpreopt(ctx, dexOutputPath)
} else {
// This should never happen as a variant for a prebuilt_apex is only created if the
// prebuilt_apex has been configured to export the java library dex file.
- ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt_apex %q", deapexerModule.Name())
+ ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt APEX %s", di.ApexModuleName())
}
}
}
@@ -2244,14 +2348,14 @@ func (module *SdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleCont
}
// to satisfy UsesLibraryDependency interface
-func (module *SdkLibraryImport) DexJarBuildPath() android.Path {
+func (module *SdkLibraryImport) DexJarBuildPath() OptionalDexJarPath {
// The dex implementation jar extracted from the .apex file should be used in preference to the
// source.
- if module.dexJarFile != nil {
+ if module.dexJarFile.IsSet() {
return module.dexJarFile
}
if module.implLibraryModule == nil {
- return nil
+ return makeUnsetDexJarPath()
} else {
return module.implLibraryModule.DexJarBuildPath()
}
@@ -2259,11 +2363,7 @@ func (module *SdkLibraryImport) DexJarBuildPath() android.Path {
// to satisfy UsesLibraryDependency interface
func (module *SdkLibraryImport) DexJarInstallPath() android.Path {
- if module.implLibraryModule == nil {
- return nil
- } else {
- return module.implLibraryModule.DexJarInstallPath()
- }
+ return module.installFile
}
// to satisfy UsesLibraryDependency interface
@@ -2289,17 +2389,17 @@ func (module *SdkLibraryImport) LintDepSets() LintDepSets {
}
}
-func (module *SdkLibraryImport) getStrictUpdatabilityLinting() bool {
+func (module *SdkLibraryImport) GetStrictUpdatabilityLinting() bool {
if module.implLibraryModule == nil {
return false
} else {
- return module.implLibraryModule.getStrictUpdatabilityLinting()
+ return module.implLibraryModule.GetStrictUpdatabilityLinting()
}
}
-func (module *SdkLibraryImport) setStrictUpdatabilityLinting(strictLinting bool) {
+func (module *SdkLibraryImport) SetStrictUpdatabilityLinting(strictLinting bool) {
if module.implLibraryModule != nil {
- module.implLibraryModule.setStrictUpdatabilityLinting(strictLinting)
+ module.implLibraryModule.SetStrictUpdatabilityLinting(strictLinting)
}
}
@@ -2328,6 +2428,11 @@ func (module *SdkLibraryImport) ImplementationAndResourcesJars() android.Paths {
}
}
+// to satisfy java.DexpreopterInterface interface
+func (module *SdkLibraryImport) IsInstallable() bool {
+ return true
+}
+
var _ android.RequiredFilesFromPrebuiltApex = (*SdkLibraryImport)(nil)
func (module *SdkLibraryImport) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) []string {
@@ -2354,6 +2459,38 @@ type sdkLibraryXml struct {
type sdkLibraryXmlProperties struct {
// canonical name of the lib
Lib_name *string
+
+ // Signals that this shared library is part of the bootclasspath starting
+ // on the version indicated in this attribute.
+ //
+ // This will make platforms at this level and above to ignore
+ // <uses-library> tags with this library name because the library is already
+ // available
+ On_bootclasspath_since *string
+
+ // Signals that this shared library was part of the bootclasspath before
+ // (but not including) the version indicated in this attribute.
+ //
+ // The system will automatically add a <uses-library> tag with this library to
+ // apps that target any SDK less than the version indicated in this attribute.
+ On_bootclasspath_before *string
+
+ // Indicates that PackageManager should ignore this shared library if the
+ // platform is below the version indicated in this attribute.
+ //
+ // This means that the device won't recognise this library as installed.
+ Min_device_sdk *string
+
+ // Indicates that PackageManager should ignore this shared library if the
+ // platform is above the version indicated in this attribute.
+ //
+ // This means that the device won't recognise this library as installed.
+ Max_device_sdk *string
+
+ // The SdkLibrary's min api level as a string
+ //
+ // This value comes from the ApiLevel of the MinSdkVersion property.
+ Sdk_library_min_api_level *string
}
// java_sdk_library_xml builds the permission xml file for a java_sdk_library.
@@ -2430,11 +2567,90 @@ func (module *sdkLibraryXml) implPath(ctx android.ModuleContext) string {
return "/" + partition + "/framework/" + implName + ".jar"
}
+func formattedOptionalSdkLevelAttribute(ctx android.ModuleContext, attrName string, value *string) string {
+ if value == nil {
+ return ""
+ }
+ apiLevel, err := android.ApiLevelFromUser(ctx, *value)
+ if err != nil {
+ // attributes in bp files have underscores but in the xml have dashes.
+ ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"), err.Error())
+ return ""
+ }
+ if apiLevel.IsCurrent() {
+ // passing "current" would always mean a future release, never the current (or the current in
+ // progress) which means some conditions would never be triggered.
+ ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"),
+ `"current" is not an allowed value for this attribute`)
+ return ""
+ }
+ // "safeValue" is safe because it translates finalized codenames to a string
+ // with their SDK int.
+ safeValue := apiLevel.String()
+ return formattedOptionalAttribute(attrName, &safeValue)
+}
+
+// formats an attribute for the xml permissions file if the value is not null
+// returns empty string otherwise
+func formattedOptionalAttribute(attrName string, value *string) string {
+ if value == nil {
+ return ""
+ }
+ return fmt.Sprintf(` %s=\"%s\"\n`, attrName, *value)
+}
+
+func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) string {
+ libName := proptools.String(module.properties.Lib_name)
+ libNameAttr := formattedOptionalAttribute("name", &libName)
+ filePath := module.implPath(ctx)
+ filePathAttr := formattedOptionalAttribute("file", &filePath)
+ implicitFromAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-since", module.properties.On_bootclasspath_since)
+ implicitUntilAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-before", module.properties.On_bootclasspath_before)
+ minSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "min-device-sdk", module.properties.Min_device_sdk)
+ maxSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "max-device-sdk", module.properties.Max_device_sdk)
+ // <library> is understood in all android versions whereas <apex-library> is only understood from API T (and ignored before that).
+ // similarly, min_device_sdk is only understood from T. So if a library is using that, we need to use the apex-library to make sure this library is not loaded before T
+ var libraryTag string
+ if module.properties.Min_device_sdk != nil {
+ libraryTag = ` <apex-library\n`
+ } else {
+ libraryTag = ` <library\n`
+ }
+
+ return strings.Join([]string{
+ `<?xml version=\"1.0\" encoding=\"utf-8\"?>\n`,
+ `<!-- Copyright (C) 2018 The Android Open Source Project\n`,
+ `\n`,
+ ` Licensed under the Apache License, Version 2.0 (the \"License\");\n`,
+ ` you may not use this file except in compliance with the License.\n`,
+ ` You may obtain a copy of the License at\n`,
+ `\n`,
+ ` http://www.apache.org/licenses/LICENSE-2.0\n`,
+ `\n`,
+ ` Unless required by applicable law or agreed to in writing, software\n`,
+ ` distributed under the License is distributed on an \"AS IS\" BASIS,\n`,
+ ` WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n`,
+ ` See the License for the specific language governing permissions and\n`,
+ ` limitations under the License.\n`,
+ `-->\n`,
+ `<permissions>\n`,
+ libraryTag,
+ libNameAttr,
+ filePathAttr,
+ implicitFromAttr,
+ implicitUntilAttr,
+ minSdkAttr,
+ maxSdkAttr,
+ ` />\n`,
+ `</permissions>\n`}, "")
+}
+
func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
module.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
libName := proptools.String(module.properties.Lib_name)
- xmlContent := fmt.Sprintf(permissionsTemplate, libName, module.implPath(ctx))
+ module.selfValidate(ctx)
+ xmlContent := module.permissionsContents(ctx)
module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath
rule := android.NewRuleBuilder(pctx, ctx)
@@ -2449,30 +2665,105 @@ func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleConte
func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
if module.hideApexVariantFromMake {
- return []android.AndroidMkEntries{android.AndroidMkEntries{
+ return []android.AndroidMkEntries{{
Disabled: true,
}}
}
- return []android.AndroidMkEntries{android.AndroidMkEntries{
+ return []android.AndroidMkEntries{{
Class: "ETC",
OutputFile: android.OptionalPathForPath(module.outputFilePath),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_MODULE_TAGS", "optional")
- entries.SetString("LOCAL_MODULE_PATH", module.installDirPath.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", module.installDirPath.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", module.outputFilePath.Base())
},
},
}}
}
+func (module *sdkLibraryXml) selfValidate(ctx android.ModuleContext) {
+ module.validateAtLeastTAttributes(ctx)
+ module.validateMinAndMaxDeviceSdk(ctx)
+ module.validateMinMaxDeviceSdkAndModuleMinSdk(ctx)
+ module.validateOnBootclasspathBeforeRequirements(ctx)
+}
+
+func (module *sdkLibraryXml) validateAtLeastTAttributes(ctx android.ModuleContext) {
+ t := android.ApiLevelOrPanic(ctx, "Tiramisu")
+ module.attrAtLeastT(ctx, t, module.properties.Min_device_sdk, "min_device_sdk")
+ module.attrAtLeastT(ctx, t, module.properties.Max_device_sdk, "max_device_sdk")
+ module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_before, "on_bootclasspath_before")
+ module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_since, "on_bootclasspath_since")
+}
+
+func (module *sdkLibraryXml) attrAtLeastT(ctx android.ModuleContext, t android.ApiLevel, attr *string, attrName string) {
+ if attr != nil {
+ if level, err := android.ApiLevelFromUser(ctx, *attr); err == nil {
+ // we will inform the user of invalid inputs when we try to write the
+ // permissions xml file so we don't need to do it here
+ if t.GreaterThan(level) {
+ ctx.PropertyErrorf(attrName, "Attribute value needs to be at least T")
+ }
+ }
+ }
+}
+
+func (module *sdkLibraryXml) validateMinAndMaxDeviceSdk(ctx android.ModuleContext) {
+ if module.properties.Min_device_sdk != nil && module.properties.Max_device_sdk != nil {
+ min, minErr := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk)
+ max, maxErr := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk)
+ if minErr == nil && maxErr == nil {
+ // we will inform the user of invalid inputs when we try to write the
+ // permissions xml file so we don't need to do it here
+ if min.GreaterThan(max) {
+ ctx.ModuleErrorf("min_device_sdk can't be greater than max_device_sdk")
+ }
+ }
+ }
+}
+
+func (module *sdkLibraryXml) validateMinMaxDeviceSdkAndModuleMinSdk(ctx android.ModuleContext) {
+ moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level)
+ if module.properties.Min_device_sdk != nil {
+ api, err := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk)
+ if err == nil {
+ if moduleMinApi.GreaterThan(api) {
+ ctx.PropertyErrorf("min_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi)
+ }
+ }
+ }
+ if module.properties.Max_device_sdk != nil {
+ api, err := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk)
+ if err == nil {
+ if moduleMinApi.GreaterThan(api) {
+ ctx.PropertyErrorf("max_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi)
+ }
+ }
+ }
+}
+
+func (module *sdkLibraryXml) validateOnBootclasspathBeforeRequirements(ctx android.ModuleContext) {
+ moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level)
+ if module.properties.On_bootclasspath_before != nil {
+ t := android.ApiLevelOrPanic(ctx, "Tiramisu")
+ // if we use the attribute, then we need to do this validation
+ if moduleMinApi.LessThan(t) {
+ // if minAPi is < T, then we need to have min_device_sdk (which only accepts T+)
+ if module.properties.Min_device_sdk == nil {
+ ctx.PropertyErrorf("on_bootclasspath_before", "Using this property requires that the module's min_sdk_version or the shared library's min_device_sdk is at least T")
+ }
+ }
+ }
+}
+
type sdkLibrarySdkMemberType struct {
android.SdkMemberTypeBase
}
-func (s *sdkLibrarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
- mctx.AddVariationDependencies(nil, dependencyTag, names...)
+func (s *sdkLibrarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ ctx.AddVariationDependencies(nil, dependencyTag, names...)
}
func (s *sdkLibrarySdkMemberType) IsInstance(module android.Module) bool {
@@ -2499,7 +2790,7 @@ type sdkLibrarySdkMemberProperties struct {
android.SdkMemberPropertiesBase
// Scope to per scope properties.
- Scopes map[*apiScope]scopeProperties
+ Scopes map[*apiScope]*scopeProperties
// The Java stubs source files.
Stub_srcs []string
@@ -2518,6 +2809,33 @@ type sdkLibrarySdkMemberProperties struct {
Doctag_paths android.Paths
Permitted_packages []string
+
+ // Signals that this shared library is part of the bootclasspath starting
+ // on the version indicated in this attribute.
+ //
+ // This will make platforms at this level and above to ignore
+ // <uses-library> tags with this library name because the library is already
+ // available
+ On_bootclasspath_since *string
+
+ // Signals that this shared library was part of the bootclasspath before
+ // (but not including) the version indicated in this attribute.
+ //
+ // The system will automatically add a <uses-library> tag with this library to
+ // apps that target any SDK less than the version indicated in this attribute.
+ On_bootclasspath_before *string
+
+ // Indicates that PackageManager should ignore this shared library if the
+ // platform is below the version indicated in this attribute.
+ //
+ // This means that the device won't recognise this library as installed.
+ Min_device_sdk *string
+
+ // Indicates that PackageManager should ignore this shared library if the
+ // platform is above the version indicated in this attribute.
+ //
+ // This means that the device won't recognise this library as installed.
+ Max_device_sdk *string
}
type scopeProperties struct {
@@ -2525,13 +2843,14 @@ type scopeProperties struct {
StubsSrcJar android.Path
CurrentApiFile android.Path
RemovedApiFile android.Path
+ AnnotationsZip android.Path `supported_build_releases:"Tiramisu+"`
SdkVersion string
}
func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
sdk := variant.(*SdkLibrary)
- s.Scopes = make(map[*apiScope]scopeProperties)
+ s.Scopes = make(map[*apiScope]*scopeProperties)
for _, apiScope := range allApiScopes {
paths := sdk.findScopePaths(apiScope)
if paths == nil {
@@ -2550,7 +2869,11 @@ func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMembe
if paths.removedApiFilePath.Valid() {
properties.RemovedApiFile = paths.removedApiFilePath.Path()
}
- s.Scopes[apiScope] = properties
+ // The annotations zip is only available for modules that set annotations_enabled: true.
+ if paths.annotationsZip.Valid() {
+ properties.AnnotationsZip = paths.annotationsZip.Path()
+ }
+ s.Scopes[apiScope] = &properties
}
}
@@ -2559,6 +2882,10 @@ func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMembe
s.Compile_dex = sdk.dexProperties.Compile_dex
s.Doctag_paths = sdk.doctagPaths
s.Permitted_packages = sdk.PermittedPackagesForUpdatableBootJars()
+ s.On_bootclasspath_since = sdk.commonSdkLibraryProperties.On_bootclasspath_since
+ s.On_bootclasspath_before = sdk.commonSdkLibraryProperties.On_bootclasspath_before
+ s.Min_device_sdk = sdk.commonSdkLibraryProperties.Min_device_sdk
+ s.Max_device_sdk = sdk.commonSdkLibraryProperties.Max_device_sdk
}
func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
@@ -2614,6 +2941,12 @@ func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberCo
scopeSet.AddProperty("removed_api", removedApiSnapshotPath)
}
+ if properties.AnnotationsZip != nil {
+ annotationsSnapshotPath := filepath.Join(scopeDir, ctx.Name()+"_annotations.zip")
+ ctx.SnapshotBuilder().CopyToSnapshot(properties.AnnotationsZip, annotationsSnapshotPath)
+ scopeSet.AddProperty("annotations", annotationsSnapshotPath)
+ }
+
if properties.SdkVersion != "" {
scopeSet.AddProperty("sdk_version", properties.SdkVersion)
}
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 65af95314..3500c84d2 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -15,12 +15,13 @@
package java
import (
- "android/soong/android"
"fmt"
"path/filepath"
"regexp"
"testing"
+ "android/soong/android"
+
"github.com/google/blueprint/proptools"
)
@@ -47,6 +48,7 @@ func TestJavaSdkLibrary(t *testing.T) {
name: "bar",
srcs: ["a.java", "b.java"],
api_packages: ["bar"],
+ exclude_kotlinc_generated_files: true,
}
java_library {
name: "baz",
@@ -107,7 +109,7 @@ func TestJavaSdkLibrary(t *testing.T) {
libs: ["foo"],
sdk_version: "module_30",
}
- `)
+ `)
// check the existence of the internal modules
foo := result.ModuleForTests("foo", "android_common")
@@ -122,7 +124,7 @@ func TestJavaSdkLibrary(t *testing.T) {
result.ModuleForTests("foo.api.system.28", "")
result.ModuleForTests("foo.api.test.28", "")
- exportedComponentsInfo := result.ModuleProvider(foo.Module(), ExportedComponentsInfoProvider).(ExportedComponentsInfo)
+ exportedComponentsInfo := result.ModuleProvider(foo.Module(), android.ExportedComponentsInfoProvider).(android.ExportedComponentsInfo)
expectedFooExportedComponents := []string{
"foo.stubs",
"foo.stubs.source",
@@ -156,9 +158,198 @@ func TestJavaSdkLibrary(t *testing.T) {
// test if baz has exported SDK lib names foo and bar to qux
qux := result.ModuleForTests("qux", "android_common")
if quxLib, ok := qux.Module().(*Library); ok {
- sdkLibs := quxLib.ClassLoaderContexts().UsesLibs()
- android.AssertDeepEquals(t, "qux exports", []string{"foo", "bar", "fred", "quuz"}, sdkLibs)
+ requiredSdkLibs, optionalSdkLibs := quxLib.ClassLoaderContexts().UsesLibs()
+ android.AssertDeepEquals(t, "qux exports (required)", []string{"fred", "quuz", "foo", "bar"}, requiredSdkLibs)
+ android.AssertDeepEquals(t, "qux exports (optional)", []string{}, optionalSdkLibs)
}
+
+ fooDexJar := result.ModuleForTests("foo", "android_common").Rule("d8")
+ // tests if kotlinc generated files are NOT excluded from output of foo.
+ android.AssertStringDoesNotContain(t, "foo dex", fooDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/*.kotlin_module")
+
+ barDexJar := result.ModuleForTests("bar", "android_common").Rule("d8")
+ // tests if kotlinc generated files are excluded from output of bar.
+ android.AssertStringDoesContain(t, "bar dex", barDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/*.kotlin_module")
+}
+
+func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithPrebuiltApis(map[string][]string{
+ "28": {"foo"},
+ "29": {"foo"},
+ "30": {"foo", "fooUpdatable", "fooUpdatableErr"},
+ }),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V", "W", "X"}
+ }),
+ ).RunTestWithBp(t,
+ `
+ java_sdk_library {
+ name: "fooUpdatable",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ on_bootclasspath_since: "U",
+ on_bootclasspath_before: "V",
+ min_device_sdk: "W",
+ max_device_sdk: "X",
+ min_sdk_version: "S",
+ }
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ }
+`)
+
+ // test that updatability attributes are passed on correctly
+ fooUpdatable := result.ModuleForTests("fooUpdatable.xml", "android_common").Rule("java_sdk_xml")
+ android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `on-bootclasspath-since=\"U\"`)
+ android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `on-bootclasspath-before=\"V\"`)
+ android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `min-device-sdk=\"W\"`)
+ android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `max-device-sdk=\"X\"`)
+
+ // double check that updatability attributes are not written if they don't exist in the bp file
+ // the permissions file for the foo library defined above
+ fooPermissions := result.ModuleForTests("foo.xml", "android_common").Rule("java_sdk_xml")
+ android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `on-bootclasspath-since`)
+ android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `on-bootclasspath-before`)
+ android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `min-device-sdk`)
+ android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `max-device-sdk`)
+}
+
+func TestJavaSdkLibrary_UpdatableLibrary_Validation_ValidVersion(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithPrebuiltApis(map[string][]string{
+ "30": {"fooUpdatable", "fooUpdatableErr"},
+ }),
+ ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(
+ []string{
+ `on_bootclasspath_since: "aaa" could not be parsed as an integer and is not a recognized codename`,
+ `on_bootclasspath_before: "bbc" could not be parsed as an integer and is not a recognized codename`,
+ `min_device_sdk: "ccc" could not be parsed as an integer and is not a recognized codename`,
+ `max_device_sdk: "current" is not an allowed value for this attribute`,
+ })).RunTestWithBp(t,
+ `
+ java_sdk_library {
+ name: "fooUpdatableErr",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ on_bootclasspath_since: "aaa",
+ on_bootclasspath_before: "bbc",
+ min_device_sdk: "ccc",
+ max_device_sdk: "current",
+ }
+`)
+}
+
+func TestJavaSdkLibrary_UpdatableLibrary_Validation_AtLeastTAttributes(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithPrebuiltApis(map[string][]string{
+ "28": {"foo"},
+ }),
+ ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(
+ []string{
+ "on_bootclasspath_since: Attribute value needs to be at least T",
+ "on_bootclasspath_before: Attribute value needs to be at least T",
+ "min_device_sdk: Attribute value needs to be at least T",
+ "max_device_sdk: Attribute value needs to be at least T",
+ },
+ )).RunTestWithBp(t,
+ `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ on_bootclasspath_since: "S",
+ on_bootclasspath_before: "S",
+ min_device_sdk: "S",
+ max_device_sdk: "S",
+ min_sdk_version: "S",
+ }
+`)
+}
+
+func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdk(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithPrebuiltApis(map[string][]string{
+ "28": {"foo"},
+ }),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V"}
+ }),
+ ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(
+ []string{
+ "min_device_sdk can't be greater than max_device_sdk",
+ },
+ )).RunTestWithBp(t,
+ `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ min_device_sdk: "V",
+ max_device_sdk: "U",
+ min_sdk_version: "S",
+ }
+`)
+}
+
+func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdkAndModuleMinSdk(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithPrebuiltApis(map[string][]string{
+ "28": {"foo"},
+ }),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V"}
+ }),
+ ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(
+ []string{
+ regexp.QuoteMeta("min_device_sdk: Can't be less than module's min sdk (V)"),
+ regexp.QuoteMeta("max_device_sdk: Can't be less than module's min sdk (V)"),
+ },
+ )).RunTestWithBp(t,
+ `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ min_device_sdk: "U",
+ max_device_sdk: "U",
+ min_sdk_version: "V",
+ }
+`)
+}
+
+func TestJavaSdkLibrary_UpdatableLibrary_usesNewTag(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithPrebuiltApis(map[string][]string{
+ "30": {"foo"},
+ }),
+ ).RunTestWithBp(t,
+ `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ min_device_sdk: "Tiramisu",
+ min_sdk_version: "S",
+ }
+`)
+ // test that updatability attributes are passed on correctly
+ fooUpdatable := result.ModuleForTests("foo.xml", "android_common").Rule("java_sdk_xml")
+ android.AssertStringDoesContain(t, "foo.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `<apex-library`)
+ android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `<library`)
}
func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) {
@@ -247,7 +438,7 @@ func TestJavaSdkLibrary_DoNotAccessImplWhenItIsNotBuilt(t *testing.T) {
}
}
-func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) {
+func TestJavaSdkLibrary_AccessOutputFiles(t *testing.T) {
android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
@@ -257,6 +448,31 @@ func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) {
name: "foo",
srcs: ["a.java"],
api_packages: ["foo"],
+ annotations_enabled: true,
+ public: {
+ enabled: true,
+ },
+ }
+ java_library {
+ name: "bar",
+ srcs: ["b.java", ":foo{.public.stubs.source}"],
+ java_resources: [":foo{.public.annotations.zip}"],
+ }
+ `)
+}
+
+func TestJavaSdkLibrary_AccessOutputFiles_NoAnnotations(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "bar" variant "android_common": path dependency ":foo{.public.annotations.zip}": annotations.zip not available for api scope public`)).
+ RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ api_packages: ["foo"],
public: {
enabled: true,
},
@@ -265,6 +481,7 @@ func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) {
java_library {
name: "bar",
srcs: ["b.java", ":foo{.public.stubs.source}"],
+ java_resources: [":foo{.public.annotations.zip}"],
}
`)
}
@@ -328,6 +545,7 @@ func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) {
stub_srcs: ["a.java"],
current_api: "api/current.txt",
removed_api: "api/removed.txt",
+ annotations: "x/annotations.zip",
},
}
@@ -337,6 +555,7 @@ func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) {
java_resources: [
":foo{.public.api.txt}",
":foo{.public.removed-api.txt}",
+ ":foo{.public.annotations.zip}",
],
}
`)
@@ -597,6 +816,7 @@ func TestJavaSdkLibraryImport(t *testing.T) {
}
CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
+ `dex2oatd`,
`prebuilt_sdklib.stubs`,
`prebuilt_sdklib.stubs.source.test`,
`prebuilt_sdklib.stubs.system`,
@@ -673,7 +893,6 @@ func TestJavaSdkLibraryImport_Preferred(t *testing.T) {
`)
CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
- `dex2oatd`,
`prebuilt_sdklib`,
`sdklib.impl`,
`sdklib.stubs`,
@@ -682,6 +901,7 @@ func TestJavaSdkLibraryImport_Preferred(t *testing.T) {
})
CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{
+ `dex2oatd`,
`prebuilt_sdklib.stubs`,
`sdklib.impl`,
`sdklib.xml`,
@@ -930,3 +1150,87 @@ func TestJavaSdkLibraryDist(t *testing.T) {
})
}
}
+
+func TestSdkLibrary_CheckMinSdkVersion(t *testing.T) {
+ preparer := android.GroupFixturePreparers(
+ PrepareForTestWithJavaBuildComponents,
+ PrepareForTestWithJavaDefaultModules,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ )
+
+ preparer.RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ static_libs: ["util"],
+ min_sdk_version: "30",
+ unsafe_ignore_missing_latest_api: true,
+ }
+
+ java_library {
+ name: "util",
+ srcs: ["a.java"],
+ min_sdk_version: "30",
+ }
+ `)
+
+ preparer.
+ RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ libs: ["util"],
+ impl_only_libs: ["util"],
+ stub_only_libs: ["util"],
+ stub_only_static_libs: ["util"],
+ min_sdk_version: "30",
+ unsafe_ignore_missing_latest_api: true,
+ }
+
+ java_library {
+ name: "util",
+ srcs: ["a.java"],
+ }
+ `)
+
+ preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "util".*should support min_sdk_version\(30\)`)).
+ RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ static_libs: ["util"],
+ min_sdk_version: "30",
+ unsafe_ignore_missing_latest_api: true,
+ }
+
+ java_library {
+ name: "util",
+ srcs: ["a.java"],
+ min_sdk_version: "31",
+ }
+ `)
+
+ preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "another_util".*should support min_sdk_version\(30\)`)).
+ RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ static_libs: ["util"],
+ min_sdk_version: "30",
+ unsafe_ignore_missing_latest_api: true,
+ }
+
+ java_library {
+ name: "util",
+ srcs: ["a.java"],
+ static_libs: ["another_util"],
+ min_sdk_version: "30",
+ }
+
+ java_library {
+ name: "another_util",
+ srcs: ["a.java"],
+ min_sdk_version: "31",
+ }
+ `)
+}
diff --git a/java/sdk_test.go b/java/sdk_test.go
index bb595a54e..9e8ba6ed0 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -25,27 +25,36 @@ import (
"android/soong/java/config"
)
+type classpathTestCase struct {
+ name string
+ unbundled bool
+ moduleType string
+ host android.OsClass
+ properties string
+
+ // for java 8
+ bootclasspath []string
+ java8classpath []string
+
+ // for java 9
+ system string
+ java9classpath []string
+
+ forces8 bool // if set, javac will always be called with java 8 arguments
+
+ aidl string
+
+ // Indicates how this test case is affected by the setting of Always_use_prebuilt_sdks.
+ //
+ // If this is nil then the test case is unaffected by the setting of Always_use_prebuilt_sdks.
+ // Otherwise, the test case can only be used when
+ // Always_use_prebuilt_sdks=*forAlwaysUsePrebuiltSdks.
+ forAlwaysUsePrebuiltSdks *bool
+}
+
func TestClasspath(t *testing.T) {
const frameworkAidl = "-I" + defaultJavaDir + "/framework/aidl"
- var classpathTestcases = []struct {
- name string
- unbundled bool
- moduleType string
- host android.OsClass
- properties string
-
- // for java 8
- bootclasspath []string
- java8classpath []string
-
- // for java 9
- system string
- java9classpath []string
-
- forces8 bool // if set, javac will always be called with java 8 arguments
-
- aidl string
- }{
+ var classpathTestcases = []classpathTestCase{
{
name: "default",
bootclasspath: config.StableCorePlatformBootclasspathLibraries,
@@ -91,25 +100,52 @@ func TestClasspath(t *testing.T) {
aidl: "-pprebuilts/sdk/30/public/framework.aidl",
},
{
+ // Test case only applies when Always_use_prebuilt_sdks=false (the default).
+ forAlwaysUsePrebuiltSdks: proptools.BoolPtr(false),
name: "current",
properties: `sdk_version: "current",`,
bootclasspath: []string{"android_stubs_current", "core-lambda-stubs"},
- system: "core-current-stubs-system-modules",
+ system: "core-public-stubs-system-modules",
java9classpath: []string{"android_stubs_current"},
aidl: "-pout/soong/framework.aidl",
},
{
+ // Test case only applies when Always_use_prebuilt_sdks=true.
+ forAlwaysUsePrebuiltSdks: proptools.BoolPtr(true),
+
+ name: "current",
+ properties: `sdk_version: "current",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_public_current_system_modules",
+ java8classpath: []string{"prebuilts/sdk/current/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/current/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/current/public/framework.aidl",
+ },
+ {
+ // Test case only applies when Always_use_prebuilt_sdks=false (the default).
+ forAlwaysUsePrebuiltSdks: proptools.BoolPtr(false),
name: "system_current",
properties: `sdk_version: "system_current",`,
bootclasspath: []string{"android_system_stubs_current", "core-lambda-stubs"},
- system: "core-current-stubs-system-modules",
+ system: "core-public-stubs-system-modules",
java9classpath: []string{"android_system_stubs_current"},
aidl: "-pout/soong/framework.aidl",
},
{
+ // Test case only applies when Always_use_prebuilt_sdks=true.
+ forAlwaysUsePrebuiltSdks: proptools.BoolPtr(true),
+ name: "system_current",
+ properties: `sdk_version: "system_current",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_public_current_system_modules",
+ java8classpath: []string{"prebuilts/sdk/current/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/current/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/current/public/framework.aidl",
+ },
+ {
name: "system_29",
properties: `sdk_version: "system_29",`,
bootclasspath: []string{`""`},
@@ -118,7 +154,6 @@ func TestClasspath(t *testing.T) {
aidl: "-pprebuilts/sdk/29/public/framework.aidl",
},
{
-
name: "system_30",
properties: `sdk_version: "system_30",`,
bootclasspath: []string{`""`},
@@ -128,20 +163,57 @@ func TestClasspath(t *testing.T) {
aidl: "-pprebuilts/sdk/30/public/framework.aidl",
},
{
+ // Test case only applies when Always_use_prebuilt_sdks=false (the default).
+ forAlwaysUsePrebuiltSdks: proptools.BoolPtr(false),
name: "test_current",
properties: `sdk_version: "test_current",`,
bootclasspath: []string{"android_test_stubs_current", "core-lambda-stubs"},
- system: "core-current-stubs-system-modules",
+ system: "core-public-stubs-system-modules",
java9classpath: []string{"android_test_stubs_current"},
aidl: "-pout/soong/framework.aidl",
},
{
+ // Test case only applies when Always_use_prebuilt_sdks=true.
+ forAlwaysUsePrebuiltSdks: proptools.BoolPtr(true),
+
+ name: "test_current",
+ properties: `sdk_version: "test_current",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_public_current_system_modules",
+ java8classpath: []string{"prebuilts/sdk/current/test/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/current/test/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/current/public/framework.aidl",
+ },
+ {
+ name: "test_30",
+ properties: `sdk_version: "test_30",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_public_30_system_modules",
+ java8classpath: []string{"prebuilts/sdk/30/test/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/30/test/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/30/public/framework.aidl",
+ },
+ {
+ // Test case only applies when Always_use_prebuilt_sdks=false (the default).
+ forAlwaysUsePrebuiltSdks: proptools.BoolPtr(false),
name: "core_current",
properties: `sdk_version: "core_current",`,
bootclasspath: []string{"core.current.stubs", "core-lambda-stubs"},
- system: "core-current-stubs-system-modules",
+ system: "core-public-stubs-system-modules",
+ },
+ {
+ // Test case only applies when Always_use_prebuilt_sdks=true.
+ forAlwaysUsePrebuiltSdks: proptools.BoolPtr(true),
+
+ name: "core_current",
+ properties: `sdk_version: "core_current",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_public_current_system_modules",
+ java8classpath: []string{"prebuilts/sdk/current/core/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/current/core/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/current/public/framework.aidl",
},
{
@@ -214,8 +286,10 @@ func TestClasspath(t *testing.T) {
java9classpath: []string{"prebuilts/sdk/current/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
aidl: "-pprebuilts/sdk/current/public/framework.aidl",
},
-
{
+ // Test case only applies when Always_use_prebuilt_sdks=false (the default).
+ forAlwaysUsePrebuiltSdks: proptools.BoolPtr(false),
+
name: "module_current",
properties: `sdk_version: "module_current",`,
bootclasspath: []string{"android_module_lib_stubs_current", "core-lambda-stubs"},
@@ -224,6 +298,48 @@ func TestClasspath(t *testing.T) {
aidl: "-pout/soong/framework_non_updatable.aidl",
},
{
+ // Test case only applies when Always_use_prebuilt_sdks=true.
+ forAlwaysUsePrebuiltSdks: proptools.BoolPtr(true),
+
+ name: "module_current",
+ properties: `sdk_version: "module_current",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_module-lib_current_system_modules",
+ java8classpath: []string{"prebuilts/sdk/current/module-lib/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/current/module-lib/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/current/public/framework.aidl",
+ },
+ {
+ name: "module_30",
+ properties: `sdk_version: "module_30",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_public_30_system_modules",
+ java8classpath: []string{"prebuilts/sdk/30/module-lib/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/30/module-lib/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/30/public/framework.aidl",
+ },
+ {
+ name: "module_31",
+ properties: `sdk_version: "module_31",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_public_31_system_modules",
+ java8classpath: []string{"prebuilts/sdk/31/module-lib/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/31/module-lib/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/31/public/framework.aidl",
+ },
+ {
+ name: "module_32",
+ properties: `sdk_version: "module_32",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_module-lib_32_system_modules",
+ java8classpath: []string{"prebuilts/sdk/32/module-lib/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/32/module-lib/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/32/public/framework.aidl",
+ },
+ {
+ // Test case only applies when Always_use_prebuilt_sdks=false (the default).
+ forAlwaysUsePrebuiltSdks: proptools.BoolPtr(false),
+
name: "system_server_current",
properties: `sdk_version: "system_server_current",`,
bootclasspath: []string{"android_system_server_stubs_current", "core-lambda-stubs"},
@@ -231,9 +347,62 @@ func TestClasspath(t *testing.T) {
java9classpath: []string{"android_system_server_stubs_current"},
aidl: "-pout/soong/framework.aidl",
},
+ {
+ // Test case only applies when Always_use_prebuilt_sdks=true.
+ forAlwaysUsePrebuiltSdks: proptools.BoolPtr(true),
+
+ name: "system_server_current",
+ properties: `sdk_version: "system_server_current",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_module-lib_current_system_modules",
+ java8classpath: []string{"prebuilts/sdk/current/system-server/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/current/system-server/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/current/public/framework.aidl",
+ },
+ {
+ name: "system_server_30",
+ properties: `sdk_version: "system_server_30",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_public_30_system_modules",
+ java8classpath: []string{"prebuilts/sdk/30/system-server/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/30/system-server/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/30/public/framework.aidl",
+ },
+ {
+ name: "system_server_31",
+ properties: `sdk_version: "system_server_31",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_public_31_system_modules",
+ java8classpath: []string{"prebuilts/sdk/31/system-server/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/31/system-server/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/31/public/framework.aidl",
+ },
+ {
+ name: "system_server_32",
+ properties: `sdk_version: "system_server_32",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_module-lib_32_system_modules",
+ java8classpath: []string{"prebuilts/sdk/32/system-server/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/32/system-server/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/32/public/framework.aidl",
+ },
}
+ t.Run("basic", func(t *testing.T) {
+ testClasspathTestCases(t, classpathTestcases, false)
+ })
+
+ t.Run("Always_use_prebuilt_sdks=true", func(t *testing.T) {
+ testClasspathTestCases(t, classpathTestcases, true)
+ })
+}
+
+func testClasspathTestCases(t *testing.T, classpathTestcases []classpathTestCase, alwaysUsePrebuiltSdks bool) {
for _, testcase := range classpathTestcases {
+ if testcase.forAlwaysUsePrebuiltSdks != nil && *testcase.forAlwaysUsePrebuiltSdks != alwaysUsePrebuiltSdks {
+ continue
+ }
+
t.Run(testcase.name, func(t *testing.T) {
moduleType := "java_library"
if testcase.moduleType != "" {
@@ -255,9 +424,11 @@ func TestClasspath(t *testing.T) {
` + testcase.properties + `
}`
- variant := "android_common"
- if testcase.host == android.Host {
- variant = android.BuildOs.String() + "_common"
+ variant := func(result *android.TestResult) string {
+ if testcase.host == android.Host {
+ return result.Config.BuildOS.String() + "_common"
+ }
+ return "android_common"
}
convertModulesToPaths := func(cp []string) []string {
@@ -297,7 +468,9 @@ func TestClasspath(t *testing.T) {
system = "--system=none"
} else if testcase.system != "" {
dir := ""
- if strings.HasPrefix(testcase.system, "sdk_public_") {
+ // If the system modules name starts with sdk_ then it is a prebuilt module and so comes
+ // from the prebuilt directory.
+ if strings.HasPrefix(testcase.system, "sdk_") {
dir = "prebuilts/sdk"
} else {
dir = defaultJavaDir
@@ -312,7 +485,7 @@ func TestClasspath(t *testing.T) {
}
checkClasspath := func(t *testing.T, result *android.TestResult, isJava8 bool) {
- foo := result.ModuleForTests("foo", variant)
+ foo := result.ModuleForTests("foo", variant(result))
javac := foo.Rule("javac")
var deps []string
@@ -349,11 +522,20 @@ func TestClasspath(t *testing.T) {
android.AssertPathsRelativeToTopEquals(t, "implicits", deps, javac.Implicits)
}
+ preparer := android.NullFixturePreparer
+ if alwaysUsePrebuiltSdks {
+ preparer = android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
+ })
+ }
+
fixtureFactory := android.GroupFixturePreparers(
prepareForJavaTest,
FixtureWithPrebuiltApis(map[string][]string{
"29": {},
"30": {},
+ "31": {},
+ "32": {},
"current": {},
}),
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
@@ -367,6 +549,7 @@ func TestClasspath(t *testing.T) {
env["ANDROID_JAVA8_HOME"] = "jdk8"
}
}),
+ preparer,
)
// Test with legacy javac -source 1.8 -target 1.8
@@ -376,7 +559,7 @@ func TestClasspath(t *testing.T) {
checkClasspath(t, result, true /* isJava8 */)
if testcase.host != android.Host {
- aidl := result.ModuleForTests("foo", variant).Rule("aidl")
+ aidl := result.ModuleForTests("foo", variant(result)).Rule("aidl")
android.AssertStringDoesContain(t, "aidl command", aidl.RuleParams.Command, testcase.aidl+" -I.")
}
@@ -389,7 +572,7 @@ func TestClasspath(t *testing.T) {
checkClasspath(t, result, false /* isJava8 */)
if testcase.host != android.Host {
- aidl := result.ModuleForTests("foo", variant).Rule("aidl")
+ aidl := result.ModuleForTests("foo", variant(result)).Rule("aidl")
android.AssertStringDoesContain(t, "aidl command", aidl.RuleParams.Command, testcase.aidl+" -I.")
}
diff --git a/java/system_modules.go b/java/system_modules.go
index d0dc74adc..fec8ebaeb 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -245,8 +245,8 @@ type systemModulesSdkMemberType struct {
android.SdkMemberTypeBase
}
-func (mt *systemModulesSdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
- mctx.AddVariationDependencies(nil, dependencyTag, names...)
+func (mt *systemModulesSdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ ctx.AddVariationDependencies(nil, dependencyTag, names...)
}
func (mt *systemModulesSdkMemberType) IsInstance(module android.Module) bool {
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index a2006b778..fa61ea68c 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -23,11 +23,19 @@ import (
func init() {
registerSystemserverClasspathBuildComponents(android.InitRegistrationContext)
+
+ android.RegisterSdkMemberType(&systemServerClasspathFragmentMemberType{
+ SdkMemberTypeBase: android.SdkMemberTypeBase{
+ PropertyName: "systemserverclasspath_fragments",
+ SupportsSdk: true,
+ },
+ })
}
func registerSystemserverClasspathBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("platform_systemserverclasspath", platformSystemServerClasspathFactory)
ctx.RegisterModuleType("systemserverclasspath_fragment", systemServerClasspathFactory)
+ ctx.RegisterModuleType("prebuilt_systemserverclasspath_fragment", prebuiltSystemServerClasspathModuleFactory)
}
type platformSystemServerClasspathModule struct {
@@ -48,22 +56,35 @@ func (p *platformSystemServerClasspathModule) AndroidMkEntries() (entries []andr
}
func (p *platformSystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- classpathJars := configuredJarListToClasspathJars(ctx, p.ClasspathFragmentToConfiguredJarList(ctx), p.classpathType)
- p.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, classpathJars)
+ configuredJars := p.configuredJars(ctx)
+ classpathJars := configuredJarListToClasspathJars(ctx, configuredJars, p.classpathType)
+ standaloneConfiguredJars := p.standaloneConfiguredJars(ctx)
+ standaloneClasspathJars := configuredJarListToClasspathJars(ctx, standaloneConfiguredJars, STANDALONE_SYSTEMSERVER_JARS)
+ configuredJars = configuredJars.AppendList(&standaloneConfiguredJars)
+ classpathJars = append(classpathJars, standaloneClasspathJars...)
+ p.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars)
}
-func (p *platformSystemServerClasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
- global := dexpreopt.GetGlobalConfig(ctx)
- return global.SystemServerJars
+func (p *platformSystemServerClasspathModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList {
+ // TODO(satayev): include any apex jars that don't populate their classpath proto config.
+ return dexpreopt.GetGlobalConfig(ctx).SystemServerJars
+}
+
+func (p *platformSystemServerClasspathModule) standaloneConfiguredJars(ctx android.ModuleContext) android.ConfiguredJarList {
+ return dexpreopt.GetGlobalConfig(ctx).StandaloneSystemServerJars
}
type SystemServerClasspathModule struct {
android.ModuleBase
android.ApexModuleBase
+ android.SdkBase
ClasspathFragmentBase
properties systemServerClasspathFragmentProperties
+
+ // Collect the module directory for IDE info in java/jdeps.go.
+ modulePaths []string
}
func (s *SystemServerClasspathModule) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
@@ -71,39 +92,85 @@ func (s *SystemServerClasspathModule) ShouldSupportSdkVersion(ctx android.BaseMo
}
type systemServerClasspathFragmentProperties struct {
- // The contents of this systemserverclasspath_fragment, could be either java_library, or java_sdk_library.
+ // List of system_server classpath jars, could be either java_library, or java_sdk_library.
//
// The order of this list matters as it is the order that is used in the SYSTEMSERVERCLASSPATH.
Contents []string
+
+ // List of jars that system_server loads dynamically using separate classloaders.
+ //
+ // The order does not matter.
+ Standalone_contents []string
}
func systemServerClasspathFactory() android.Module {
m := &SystemServerClasspathModule{}
m.AddProperties(&m.properties)
android.InitApexModule(m)
+ android.InitSdkAwareModule(m)
initClasspathFragment(m, SYSTEMSERVERCLASSPATH)
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
return m
}
func (s *SystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- if len(s.properties.Contents) == 0 {
- ctx.PropertyErrorf("contents", "empty contents are not allowed")
+ if len(s.properties.Contents) == 0 && len(s.properties.Standalone_contents) == 0 {
+ ctx.PropertyErrorf("contents", "Either contents or standalone_contents needs to be non-empty")
+ }
+
+ configuredJars := s.configuredJars(ctx)
+ classpathJars := configuredJarListToClasspathJars(ctx, configuredJars, s.classpathType)
+ standaloneConfiguredJars := s.standaloneConfiguredJars(ctx)
+ standaloneClasspathJars := configuredJarListToClasspathJars(ctx, standaloneConfiguredJars, STANDALONE_SYSTEMSERVER_JARS)
+ configuredJars = configuredJars.AppendList(&standaloneConfiguredJars)
+ classpathJars = append(classpathJars, standaloneClasspathJars...)
+ s.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars)
+
+ // Collect the module directory for IDE info in java/jdeps.go.
+ s.modulePaths = append(s.modulePaths, ctx.ModuleDir())
+}
+
+func (s *SystemServerClasspathModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList {
+ global := dexpreopt.GetGlobalConfig(ctx)
+
+ possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, s.properties.Contents, systemServerClasspathFragmentContentDepTag)
+ jars, unknown := global.ApexSystemServerJars.Filter(possibleUpdatableModules)
+ // TODO(satayev): remove geotz ssc_fragment, since geotz is not part of SSCP anymore.
+ _, unknown = android.RemoveFromList("geotz", unknown)
+ // This module only exists in car products.
+ // So ignore it even if it is not in PRODUCT_APEX_SYSTEM_SERVER_JARS.
+ // TODO(b/203233647): Add better mechanism to make it optional.
+ _, unknown = android.RemoveFromList("car-frameworks-service-module", unknown)
+
+ // This module is optional, so it is not present in all products.
+ // (See PRODUCT_ISOLATED_COMPILATION_ENABLED.)
+ // So ignore it even if it is not in PRODUCT_APEX_SYSTEM_SERVER_JARS.
+ // TODO(b/203233647): Add better mechanism to make it optional.
+ _, unknown = android.RemoveFromList("service-compos", unknown)
+
+ // TODO(satayev): for apex_test we want to include all contents unconditionally to classpaths
+ // config. However, any test specific jars would not be present in ApexSystemServerJars. Instead,
+ // we should check if we are creating a config for apex_test via ApexInfo and amend the values.
+ // This is an exception to support end-to-end test for ApexdUnitTests, until such support exists.
+ if android.InList("test_service-apexd", possibleUpdatableModules) {
+ jars = jars.Append("com.android.apex.test_package", "test_service-apexd")
+ } else if global.ApexSystemServerJars.Len() > 0 && len(unknown) > 0 && !android.IsModuleInVersionedSdk(ctx.Module()) {
+ // For non test apexes, make sure that all contents are actually declared in make.
+ ctx.ModuleErrorf("%s in contents must also be declared in PRODUCT_APEX_SYSTEM_SERVER_JARS", unknown)
}
- classpathJars := configuredJarListToClasspathJars(ctx, s.ClasspathFragmentToConfiguredJarList(ctx), s.classpathType)
- s.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, classpathJars)
+ return jars
}
-func (s *SystemServerClasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
+func (s *SystemServerClasspathModule) standaloneConfiguredJars(ctx android.ModuleContext) android.ConfiguredJarList {
global := dexpreopt.GetGlobalConfig(ctx)
- possibleUpdatableModules := gatherPossibleUpdatableModuleNamesAndStems(ctx, s.properties.Contents, systemServerClasspathFragmentContentDepTag)
+ possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, s.properties.Standalone_contents, systemServerClasspathFragmentContentDepTag)
+ jars, _ := global.ApexStandaloneSystemServerJars.Filter(possibleUpdatableModules)
- // Only create configs for updatable boot jars. Non-updatable system server jars must be part of the
- // platform_systemserverclasspath's classpath proto config to guarantee that they come before any
- // updatable jars at runtime.
- return global.UpdatableSystemServerJars.Filter(possibleUpdatableModules)
+ // TODO(jiakaiz): add a check to ensure that the contents are declared in make.
+
+ return jars
}
type systemServerClasspathFragmentContentDependencyTag struct {
@@ -115,11 +182,33 @@ func (systemServerClasspathFragmentContentDependencyTag) ReplaceSourceWithPrebui
return false
}
+// SdkMemberType causes dependencies added with this tag to be automatically added to the sdk as if
+// they were specified using java_systemserver_libs or java_sdk_libs.
+func (b systemServerClasspathFragmentContentDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType {
+ // If the module is a java_sdk_library then treat it as if it was specified in the java_sdk_libs
+ // property, otherwise treat if it was specified in the java_systemserver_libs property.
+ if javaSdkLibrarySdkMemberType.IsInstance(child) {
+ return javaSdkLibrarySdkMemberType
+ }
+
+ return javaSystemserverLibsSdkMemberType
+}
+
+func (b systemServerClasspathFragmentContentDependencyTag) ExportMember() bool {
+ return true
+}
+
// Contents of system server fragments in an apex are considered to be directly in the apex, as if
// they were listed in java_libs.
func (systemServerClasspathFragmentContentDependencyTag) CopyDirectlyInAnyApex() {}
+// Contents of system server fragments require files from prebuilt apex files.
+func (systemServerClasspathFragmentContentDependencyTag) RequiresFilesFromPrebuiltApex() {}
+
+var _ android.ReplaceSourceWithPrebuilt = systemServerClasspathFragmentContentDepTag
+var _ android.SdkMemberDependencyTag = systemServerClasspathFragmentContentDepTag
var _ android.CopyDirectlyInAnyApexTag = systemServerClasspathFragmentContentDepTag
+var _ android.RequiresFilesFromPrebuiltApexTag = systemServerClasspathFragmentContentDepTag
// The tag used for the dependency between the systemserverclasspath_fragment module and its contents.
var systemServerClasspathFragmentContentDepTag = systemServerClasspathFragmentContentDependencyTag{}
@@ -130,8 +219,113 @@ func IsSystemServerClasspathFragmentContentDepTag(tag blueprint.DependencyTag) b
func (s *SystemServerClasspathModule) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
module := ctx.Module()
+ _, isSourceModule := module.(*SystemServerClasspathModule)
+ var deps []string
+ deps = append(deps, s.properties.Contents...)
+ deps = append(deps, s.properties.Standalone_contents...)
- for _, name := range s.properties.Contents {
+ for _, name := range deps {
+ // A systemserverclasspath_fragment must depend only on other source modules, while the
+ // prebuilt_systemserverclasspath_fragment_fragment must only depend on other prebuilt modules.
+ if !isSourceModule {
+ name = android.PrebuiltNameFromSource(name)
+ }
ctx.AddDependency(module, systemServerClasspathFragmentContentDepTag, name)
}
}
+
+// Collect information for opening IDE project files in java/jdeps.go.
+func (s *SystemServerClasspathModule) IDEInfo(dpInfo *android.IdeInfo) {
+ dpInfo.Deps = append(dpInfo.Deps, s.properties.Contents...)
+ dpInfo.Deps = append(dpInfo.Deps, s.properties.Standalone_contents...)
+ dpInfo.Paths = append(dpInfo.Paths, s.modulePaths...)
+}
+
+type systemServerClasspathFragmentMemberType struct {
+ android.SdkMemberTypeBase
+}
+
+func (s *systemServerClasspathFragmentMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ ctx.AddVariationDependencies(nil, dependencyTag, names...)
+}
+
+func (s *systemServerClasspathFragmentMemberType) IsInstance(module android.Module) bool {
+ _, ok := module.(*SystemServerClasspathModule)
+ return ok
+}
+
+func (s *systemServerClasspathFragmentMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_systemserverclasspath_fragment")
+}
+
+func (s *systemServerClasspathFragmentMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &systemServerClasspathFragmentSdkMemberProperties{}
+}
+
+type systemServerClasspathFragmentSdkMemberProperties struct {
+ android.SdkMemberPropertiesBase
+
+ // List of system_server classpath jars, could be either java_library, or java_sdk_library.
+ //
+ // The order of this list matters as it is the order that is used in the SYSTEMSERVERCLASSPATH.
+ Contents []string
+
+ // List of jars that system_server loads dynamically using separate classloaders.
+ //
+ // The order does not matter.
+ Standalone_contents []string
+}
+
+func (s *systemServerClasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+ module := variant.(*SystemServerClasspathModule)
+
+ s.Contents = module.properties.Contents
+ s.Standalone_contents = module.properties.Standalone_contents
+}
+
+func (s *systemServerClasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ builder := ctx.SnapshotBuilder()
+ requiredMemberDependency := builder.SdkMemberReferencePropertyTag(true)
+
+ if len(s.Contents) > 0 {
+ propertySet.AddPropertyWithTag("contents", s.Contents, requiredMemberDependency)
+ }
+
+ if len(s.Standalone_contents) > 0 {
+ propertySet.AddPropertyWithTag("standalone_contents", s.Standalone_contents, requiredMemberDependency)
+ }
+}
+
+var _ android.SdkMemberType = (*systemServerClasspathFragmentMemberType)(nil)
+
+// A prebuilt version of the systemserverclasspath_fragment module.
+type prebuiltSystemServerClasspathModule struct {
+ SystemServerClasspathModule
+ prebuilt android.Prebuilt
+}
+
+func (module *prebuiltSystemServerClasspathModule) Prebuilt() *android.Prebuilt {
+ return &module.prebuilt
+}
+
+func (module *prebuiltSystemServerClasspathModule) Name() string {
+ return module.prebuilt.Name(module.ModuleBase.Name())
+}
+
+func (module *prebuiltSystemServerClasspathModule) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) []string {
+ return nil
+}
+
+var _ android.RequiredFilesFromPrebuiltApex = (*prebuiltSystemServerClasspathModule)(nil)
+
+func prebuiltSystemServerClasspathModuleFactory() android.Module {
+ m := &prebuiltSystemServerClasspathModule{}
+ m.AddProperties(&m.properties)
+ // This doesn't actually have any prebuilt files of its own so pass a placeholder for the srcs
+ // array.
+ android.InitPrebuiltModule(m, &[]string{"placeholder"})
+ android.InitApexModule(m)
+ android.InitSdkAwareModule(m)
+ android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
+ return m
+}
diff --git a/java/systemserver_classpath_fragment_test.go b/java/systemserver_classpath_fragment_test.go
index 9ad50dd4a..ba328e7b1 100644
--- a/java/systemserver_classpath_fragment_test.go
+++ b/java/systemserver_classpath_fragment_test.go
@@ -99,7 +99,7 @@ func TestPlatformSystemServerClasspathModule_AndroidMkEntries(t *testing.T) {
func TestSystemServerClasspathFragmentWithoutContents(t *testing.T) {
prepareForTestWithSystemServerClasspath.
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
- `\Qempty contents are not allowed\E`)).
+ `\QEither contents or standalone_contents needs to be non-empty\E`)).
RunTestWithBp(t, `
systemserverclasspath_fragment {
name: "systemserverclasspath-fragment",
diff --git a/java/testing.go b/java/testing.go
index 3ef51bd4d..511cc5ddb 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -54,6 +54,8 @@ var PrepareForTestWithJavaBuildComponents = android.GroupFixturePreparers(
"build/soong/java/lint_defaults.txt": nil,
// Needed for apps that do not provide their own.
"build/make/target/product/security": nil,
+ // Required to generate Java used-by API coverage
+ "build/soong/scripts/gen_java_usedby_apex.sh": nil,
}.AddToFixture(),
)
@@ -70,6 +72,10 @@ var PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd = android.GroupFixtu
defaultJavaDir + "/framework/aidl": nil,
// Needed for various deps defined in GatherRequiredDepsForTest()
defaultJavaDir + "/a.java": nil,
+
+ // Needed for R8 rules on apps
+ "build/make/core/proguard.flags": nil,
+ "build/make/core/proguard_basic_keeps.flags": nil,
}.AddToFixture(),
// The java default module definitions.
android.FixtureAddTextFile(defaultJavaDir+"/Android.bp", gatherRequiredDepsForTest()),
@@ -146,6 +152,10 @@ var PrepareForTestWithPrebuiltsOfCurrentApi = FixtureWithPrebuiltApis(map[string
// This defines a file in the mock file system in a predefined location (prebuilts/sdk/Android.bp)
// and so only one instance of this can be used in each fixture.
func FixtureWithPrebuiltApis(release2Modules map[string][]string) android.FixturePreparer {
+ return FixtureWithPrebuiltApisAndExtensions(release2Modules, nil)
+}
+
+func FixtureWithPrebuiltApisAndExtensions(apiLevel2Modules map[string][]string, extensionLevel2Modules map[string][]string) android.FixturePreparer {
mockFS := android.MockFS{}
path := "prebuilts/sdk/Android.bp"
@@ -153,14 +163,19 @@ func FixtureWithPrebuiltApis(release2Modules map[string][]string) android.Fixtur
prebuilt_apis {
name: "sdk",
api_dirs: ["%s"],
+ extensions_dir: "extensions",
imports_sdk_version: "none",
imports_compile_dex: true,
}
- `, strings.Join(android.SortedStringKeys(release2Modules), `", "`))
+ `, strings.Join(android.SortedStringKeys(apiLevel2Modules), `", "`))
- for release, modules := range release2Modules {
- libs := append([]string{"android", "core-for-system-modules"}, modules...)
- mockFS.Merge(prebuiltApisFilesForLibs([]string{release}, libs))
+ for release, modules := range apiLevel2Modules {
+ mockFS.Merge(prebuiltApisFilesForModules([]string{release}, modules))
+ }
+ if extensionLevel2Modules != nil {
+ for release, modules := range extensionLevel2Modules {
+ mockFS.Merge(prebuiltExtensionApiFiles([]string{release}, modules))
+ }
}
return android.GroupFixturePreparers(
android.FixtureAddTextFile(path, bp),
@@ -168,24 +183,50 @@ func FixtureWithPrebuiltApis(release2Modules map[string][]string) android.Fixtur
)
}
-func prebuiltApisFilesForLibs(apiLevels []string, sdkLibs []string) map[string][]byte {
+func prebuiltApisFilesForModules(apiLevels []string, modules []string) map[string][]byte {
+ libs := append([]string{"android"}, modules...)
+
fs := make(map[string][]byte)
for _, level := range apiLevels {
- for _, lib := range sdkLibs {
- for _, scope := range []string{"public", "system", "module-lib", "system-server", "test"} {
- fs[fmt.Sprintf("prebuilts/sdk/%s/%s/%s.jar", level, scope, lib)] = nil
+ apiLevel := android.ApiLevelForTest(level)
+ for _, sdkKind := range []android.SdkKind{android.SdkPublic, android.SdkSystem, android.SdkModule, android.SdkSystemServer, android.SdkTest} {
+ // A core-for-system-modules file must only be created for the sdk kind that supports it.
+ if sdkKind == systemModuleKind(sdkKind, apiLevel) {
+ fs[fmt.Sprintf("prebuilts/sdk/%s/%s/core-for-system-modules.jar", level, sdkKind)] = nil
+ }
+
+ for _, lib := range libs {
+ // Create a jar file for every library.
+ fs[fmt.Sprintf("prebuilts/sdk/%s/%s/%s.jar", level, sdkKind, lib)] = nil
+
// No finalized API files for "current"
if level != "current" {
- fs[fmt.Sprintf("prebuilts/sdk/%s/%s/api/%s.txt", level, scope, lib)] = nil
- fs[fmt.Sprintf("prebuilts/sdk/%s/%s/api/%s-removed.txt", level, scope, lib)] = nil
+ fs[fmt.Sprintf("prebuilts/sdk/%s/%s/api/%s.txt", level, sdkKind, lib)] = nil
+ fs[fmt.Sprintf("prebuilts/sdk/%s/%s/api/%s-removed.txt", level, sdkKind, lib)] = nil
}
}
}
+ if level == "current" {
+ fs["prebuilts/sdk/current/core/android.jar"] = nil
+ }
fs[fmt.Sprintf("prebuilts/sdk/%s/public/framework.aidl", level)] = nil
}
return fs
}
+func prebuiltExtensionApiFiles(extensionLevels []string, modules []string) map[string][]byte {
+ fs := make(map[string][]byte)
+ for _, level := range extensionLevels {
+ for _, sdkKind := range []android.SdkKind{android.SdkPublic, android.SdkSystem, android.SdkModule, android.SdkSystemServer} {
+ for _, lib := range modules {
+ fs[fmt.Sprintf("prebuilts/sdk/extensions/%s/%s/api/%s.txt", level, sdkKind, lib)] = nil
+ fs[fmt.Sprintf("prebuilts/sdk/extensions/%s/%s/api/%s-removed.txt", level, sdkKind, lib)] = nil
+ }
+ }
+ }
+ return fs
+}
+
// FixtureConfigureBootJars configures the boot jars in both the dexpreopt.GlobalConfig and
// Config.productVariables structs. As a side effect that enables dexpreopt.
func FixtureConfigureBootJars(bootJars ...string) android.FixturePreparer {
@@ -214,21 +255,41 @@ func FixtureConfigureBootJars(bootJars ...string) android.FixturePreparer {
)
}
-// FixtureConfigureUpdatableBootJars configures the updatable boot jars in both the
+// FixtureConfigureApexBootJars configures the apex boot jars in both the
// dexpreopt.GlobalConfig and Config.productVariables structs. As a side effect that enables
// dexpreopt.
-func FixtureConfigureUpdatableBootJars(bootJars ...string) android.FixturePreparer {
+func FixtureConfigureApexBootJars(bootJars ...string) android.FixturePreparer {
return android.GroupFixturePreparers(
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.UpdatableBootJars = android.CreateTestConfiguredJarList(bootJars)
+ variables.ApexBootJars = android.CreateTestConfiguredJarList(bootJars)
}),
- dexpreopt.FixtureSetUpdatableBootJars(bootJars...),
+ dexpreopt.FixtureSetApexBootJars(bootJars...),
// Add a fake dex2oatd module.
dexpreopt.PrepareForTestWithFakeDex2oatd,
)
}
+// FixtureUseLegacyCorePlatformApi prepares the fixture by setting the exception list of those
+// modules that are allowed to use the legacy core platform API to be the ones supplied.
+func FixtureUseLegacyCorePlatformApi(moduleNames ...string) android.FixturePreparer {
+ lookup := make(map[string]struct{})
+ for _, moduleName := range moduleNames {
+ lookup[moduleName] = struct{}{}
+ }
+ return android.FixtureModifyConfig(func(config android.Config) {
+ // Try and set the legacyCorePlatformApiLookup in the config, the returned value will be the
+ // actual value that is set.
+ cached := config.Once(legacyCorePlatformApiLookupKey, func() interface{} {
+ return lookup
+ })
+ // Make sure that the cached value is the one we need.
+ if !reflect.DeepEqual(cached, lookup) {
+ panic(fmt.Errorf("attempting to set legacyCorePlatformApiLookupKey to %q but it has already been set to %q", lookup, cached))
+ }
+ })
+}
+
// registerRequiredBuildComponentsForTest registers the build components used by
// PrepareForTestWithJavaDefaultModules.
//
@@ -280,6 +341,7 @@ func gatherRequiredDepsForTest() string {
"kotlin-stdlib-jdk7",
"kotlin-stdlib-jdk8",
"kotlin-annotations",
+ "stub-annotations",
}
for _, extra := range extraModules {
@@ -311,7 +373,7 @@ func gatherRequiredDepsForTest() string {
}`
systemModules := []string{
- "core-current-stubs-system-modules",
+ "core-public-stubs-system-modules",
"core-module-lib-stubs-system-modules",
"legacy-core-platform-api-stubs-system-modules",
"stable-core-platform-api-stubs-system-modules",
@@ -364,6 +426,17 @@ func CheckPlatformBootclasspathModules(t *testing.T, result *android.TestResult,
android.AssertDeepEquals(t, fmt.Sprintf("%s modules", "platform-bootclasspath"), expected, pairs)
}
+func CheckClasspathFragmentProtoContentInfoProvider(t *testing.T, result *android.TestResult, generated bool, contents, outputFilename, installDir string) {
+ t.Helper()
+ p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
+ info := result.ModuleProvider(p, ClasspathFragmentProtoContentInfoProvider).(ClasspathFragmentProtoContentInfo)
+
+ android.AssertBoolEquals(t, "classpath proto generated", generated, info.ClasspathFragmentProtoGenerated)
+ android.AssertStringEquals(t, "classpath proto contents", contents, info.ClasspathFragmentProtoContents.String())
+ android.AssertStringEquals(t, "output filepath", outputFilename, info.ClasspathFragmentProtoOutput.Base())
+ android.AssertPathRelativeToTopEquals(t, "install filepath", installDir, info.ClasspathFragmentProtoInstallDir)
+}
+
// ApexNamePairsFromModules returns the apex:module pair for the supplied modules.
func ApexNamePairsFromModules(ctx *android.TestContext, modules []android.Module) []string {
pairs := []string{}
@@ -420,3 +493,61 @@ func CheckMergedCompatConfigInputs(t *testing.T, result *android.TestResult, mes
output := sourceGlobalCompatConfig.Output(allOutputs[0])
android.AssertPathsRelativeToTopEquals(t, message+": inputs", expectedPaths, output.Implicits)
}
+
+// Register the fake APEX mutator to `android.InitRegistrationContext` as if the real mutator exists
+// at runtime. This must be called in `init()` of a test if the test is going to use the fake APEX
+// mutator. Otherwise, we will be missing the runtime mutator because "soong-apex" is not a
+// dependency, which will cause an inconsistency between testing and runtime mutators.
+func RegisterFakeRuntimeApexMutator() {
+ registerFakeApexMutator(android.InitRegistrationContext)
+}
+
+var PrepareForTestWithFakeApexMutator = android.GroupFixturePreparers(
+ android.FixtureRegisterWithContext(registerFakeApexMutator),
+)
+
+func registerFakeApexMutator(ctx android.RegistrationContext) {
+ ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("apex", fakeApexMutator).Parallel()
+ })
+}
+
+type apexModuleBase interface {
+ ApexAvailable() []string
+}
+
+var _ apexModuleBase = (*Library)(nil)
+var _ apexModuleBase = (*SdkLibrary)(nil)
+
+// A fake APEX mutator that creates a platform variant and an APEX variant for modules with
+// `apex_available`. It helps us avoid a dependency on the real mutator defined in "soong-apex",
+// which will cause a cyclic dependency, and it provides an easy way to create an APEX variant for
+// testing without dealing with all the complexities in the real mutator.
+func fakeApexMutator(mctx android.BottomUpMutatorContext) {
+ switch mctx.Module().(type) {
+ case *Library, *SdkLibrary:
+ if len(mctx.Module().(apexModuleBase).ApexAvailable()) > 0 {
+ modules := mctx.CreateVariations("", "apex1000")
+ apexInfo := android.ApexInfo{
+ ApexVariationName: "apex1000",
+ }
+ mctx.SetVariationProvider(modules[1], android.ApexInfoProvider, apexInfo)
+ }
+ }
+}
+
+// Applies the given modifier on the boot image config with the given name.
+func FixtureModifyBootImageConfig(name string, configModifier func(*bootImageConfig)) android.FixturePreparer {
+ return android.FixtureModifyConfig(func(androidConfig android.Config) {
+ pathCtx := android.PathContextForTesting(androidConfig)
+ config := genBootImageConfigRaw(pathCtx)
+ configModifier(config[name])
+ })
+}
+
+// Sets the value of `installDirOnDevice` of the boot image config with the given name.
+func FixtureSetBootImageInstallDirOnDevice(name string, installDir string) android.FixturePreparer {
+ return FixtureModifyBootImageConfig(name, func(config *bootImageConfig) {
+ config.installDirOnDevice = installDir
+ })
+}