summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/aar.go17
-rw-r--r--java/androidmk.go60
-rwxr-xr-xjava/app.go276
-rw-r--r--java/app_builder.go58
-rw-r--r--java/app_test.go439
-rw-r--r--java/builder.go103
-rw-r--r--java/config/config.go6
-rw-r--r--java/dex.go59
-rw-r--r--java/dexpreopt_bootjars.go20
-rw-r--r--java/dexpreopt_bootjars_test.go71
-rw-r--r--java/dexpreopt_config.go10
-rw-r--r--java/droiddoc.go83
-rw-r--r--java/hiddenapi.go4
-rw-r--r--java/java.go148
-rw-r--r--java/java_test.go267
-rw-r--r--java/jdeps.go1
-rw-r--r--java/prebuilt_apis.go35
-rw-r--r--java/sdk.go26
-rw-r--r--java/sdk_library.go1119
-rw-r--r--java/sdk_test.go67
-rw-r--r--java/testing.go97
21 files changed, 2444 insertions, 522 deletions
diff --git a/java/aar.go b/java/aar.go
index 6e3b9e6d3..c8daf835b 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -379,8 +379,11 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati
sharedLibs = append(sharedLibs, exportPackage)
}
- if _, ok := module.(SdkLibraryDependency); ok {
- sdkLibraries = append(sdkLibraries, ctx.OtherModuleName(module))
+ // If the module is (or possibly could be) a component of a java_sdk_library
+ // (including the java_sdk_library) itself then append any implicit sdk library
+ // names to the list of sdk libraries to be added to the manifest.
+ if component, ok := module.(SdkLibraryComponentDependency); ok {
+ sdkLibraries = append(sdkLibraries, component.OptionalImplicitSdkLibrary()...)
}
case frameworkResTag:
@@ -513,6 +516,7 @@ func AndroidLibraryFactory() android.Module {
module.androidLibraryProperties.BuildAAR = true
+ android.InitApexModule(module)
InitJavaModule(module, android.DeviceSupported)
return module
}
@@ -537,8 +541,12 @@ type AARImportProperties struct {
type AARImport struct {
android.ModuleBase
android.DefaultableModuleBase
+ android.ApexModuleBase
prebuilt android.Prebuilt
+ // Functionality common to Module and Import.
+ embeddableInModuleAndImport
+
properties AARImportProperties
classpathFile android.WritablePath
@@ -742,6 +750,10 @@ func (a *AARImport) SrcJarArgs() ([]string, android.Paths) {
return nil, nil
}
+func (a *AARImport) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+ return a.depIsInSameApex(ctx, dep)
+}
+
var _ android.PrebuiltInterface = (*Import)(nil)
// android_library_import imports an `.aar` file into the build graph as if it was built with android_library.
@@ -754,6 +766,7 @@ func AARImportFactory() android.Module {
module.AddProperties(&module.properties)
android.InitPrebuiltModule(module, &module.properties.Aars)
+ android.InitApexModule(module)
InitJavaModule(module, android.DeviceSupported)
return module
}
diff --git a/java/androidmk.go b/java/androidmk.go
index 2c2919218..62cf169fa 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -69,7 +69,26 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries {
if !library.ApexModuleBase.AvailableFor(android.AvailableToPlatform) {
hideFromMake = true
}
- if !hideFromMake {
+ if hideFromMake {
+ // May still need to add some additional dependencies. This will be called
+ // once for the platform variant (even if it is not being used) and once each
+ // for the APEX specific variants. In order to avoid adding the dependency
+ // multiple times only add it for the platform variant.
+ checkedModulePaths := library.additionalCheckedModules
+ if library.IsForPlatform() && len(checkedModulePaths) != 0 {
+ mainEntries = 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(entries *android.AndroidMkEntries) {
+ entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", checkedModulePaths.Strings()...)
+ },
+ },
+ }
+ }
+ } else {
mainEntries = android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
DistFile: android.OptionalPathForPath(library.distFile),
@@ -211,6 +230,11 @@ func (prebuilt *DexImport) AndroidMkEntries() []android.AndroidMkEntries {
}
func (prebuilt *AARImport) AndroidMkEntries() []android.AndroidMkEntries {
+ if !prebuilt.IsForPlatform() {
+ return []android.AndroidMkEntries{{
+ Disabled: true,
+ }}
+ }
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
OutputFile: android.OptionalPathForPath(prebuilt.classpathFile),
@@ -416,6 +440,11 @@ func (a *AndroidTestHelperApp) AndroidMkEntries() []android.AndroidMkEntries {
}
func (a *AndroidLibrary) AndroidMkEntries() []android.AndroidMkEntries {
+ if !a.IsForPlatform() {
+ return []android.AndroidMkEntries{{
+ Disabled: true,
+ }}
+ }
entriesList := a.Library.AndroidMkEntries()
entries := &entriesList[0]
@@ -502,14 +531,12 @@ func (ddoc *Droiddoc) AndroidMkEntries() []android.AndroidMkEntries {
fmt.Fprintln(w, ddoc.Name()+"-check-last-released-api:",
ddoc.checkLastReleasedApiTimestamp.String())
- if ddoc.Name() == "api-stubs-docs" || ddoc.Name() == "system-api-stubs-docs" {
- fmt.Fprintln(w, ".PHONY: checkapi")
- fmt.Fprintln(w, "checkapi:",
- ddoc.checkLastReleasedApiTimestamp.String())
+ fmt.Fprintln(w, ".PHONY: checkapi")
+ fmt.Fprintln(w, "checkapi:",
+ ddoc.checkLastReleasedApiTimestamp.String())
- fmt.Fprintln(w, ".PHONY: droidcore")
- fmt.Fprintln(w, "droidcore: checkapi")
- }
+ fmt.Fprintln(w, ".PHONY: droidcore")
+ fmt.Fprintln(w, "droidcore: checkapi")
}
},
},
@@ -681,3 +708,20 @@ func (r *RuntimeResourceOverlay) AndroidMkEntries() []android.AndroidMkEntries {
},
}}
}
+
+func (apkSet *AndroidAppSet) AndroidMkEntries() []android.AndroidMkEntries {
+ return []android.AndroidMkEntries{
+ android.AndroidMkEntries{
+ Class: "APPS",
+ OutputFile: android.OptionalPathForPath(apkSet.packedOutput),
+ Include: "$(BUILD_SYSTEM)/soong_android_app_set.mk",
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
+ entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", apkSet.Privileged())
+ entries.SetString("LOCAL_APK_SET_MASTER_FILE", apkSet.masterFile)
+ entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", apkSet.properties.Overrides...)
+ },
+ },
+ },
+ }
+}
diff --git a/java/app.go b/java/app.go
index f1af2adf4..a45ab6f99 100755
--- a/java/app.go
+++ b/java/app.go
@@ -20,6 +20,7 @@ import (
"path/filepath"
"reflect"
"sort"
+ "strconv"
"strings"
"github.com/google/blueprint"
@@ -49,6 +50,127 @@ func RegisterAppBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("android_app_import", AndroidAppImportFactory)
ctx.RegisterModuleType("android_test_import", AndroidTestImportFactory)
ctx.RegisterModuleType("runtime_resource_overlay", RuntimeResourceOverlayFactory)
+ ctx.RegisterModuleType("android_app_set", AndroidApkSetFactory)
+}
+
+type AndroidAppSetProperties struct {
+ // APK Set path
+ Set *string
+
+ // Specifies that this app should be installed to the priv-app directory,
+ // where the system will grant it additional privileges not available to
+ // normal apps.
+ Privileged *bool
+
+ // APKs in this set use prerelease SDK version
+ Prerelease *bool
+
+ // Names of modules to be overridden. Listed modules can only be other apps
+ // (in Make or Soong).
+ Overrides []string
+}
+
+type AndroidAppSet struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+ prebuilt android.Prebuilt
+
+ properties AndroidAppSetProperties
+ packedOutput android.WritablePath
+ masterFile string
+}
+
+func (as *AndroidAppSet) Name() string {
+ return as.prebuilt.Name(as.ModuleBase.Name())
+}
+
+func (as *AndroidAppSet) IsInstallable() bool {
+ return true
+}
+
+func (as *AndroidAppSet) Prebuilt() *android.Prebuilt {
+ return &as.prebuilt
+}
+
+func (as *AndroidAppSet) Privileged() bool {
+ return Bool(as.properties.Privileged)
+}
+
+var TargetCpuAbi = map[string]string{
+ "arm": "ARMEABI_V7A",
+ "arm64": "ARM64_V8A",
+ "x86": "X86",
+ "x86_64": "X86_64",
+}
+
+func SupportedAbis(ctx android.ModuleContext) []string {
+ abiName := func(archVar string, deviceArch string) string {
+ if abi, found := TargetCpuAbi[deviceArch]; found {
+ return abi
+ }
+ ctx.ModuleErrorf("Invalid %s: %s", archVar, deviceArch)
+ return "BAD_ABI"
+ }
+
+ result := []string{abiName("TARGET_ARCH", ctx.DeviceConfig().DeviceArch())}
+ if s := ctx.DeviceConfig().DeviceSecondaryArch(); s != "" {
+ result = append(result, abiName("TARGET_2ND_ARCH", s))
+ }
+ return result
+}
+
+func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ as.packedOutput = android.PathForModuleOut(ctx, "extracted.zip")
+ // We are assuming here that the master 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.masterFile = ctx.ModuleName() + ".apk"
+ screenDensities := "all"
+ if dpis := ctx.Config().ProductAAPTPrebuiltDPI(); len(dpis) > 0 {
+ screenDensities = strings.ToUpper(strings.Join(dpis, ","))
+ }
+ // TODO(asmundak): handle locales.
+ // TODO(asmundak): do we support device features
+ ctx.Build(pctx,
+ android.BuildParams{
+ Rule: extractMatchingApks,
+ Description: "Extract APKs from APK set",
+ Output: as.packedOutput,
+ 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)),
+ "screen-densities": screenDensities,
+ "sdk-version": ctx.Config().PlatformSdkVersion(),
+ "stem": ctx.ModuleName(),
+ },
+ })
+ // TODO(asmundak): add this (it's wrong now, will cause copying extracted.zip)
+ /*
+ var installDir android.InstallPath
+ if Bool(as.properties.Privileged) {
+ installDir = android.PathForModuleInstall(ctx, "priv-app", as.BaseModuleName())
+ } else if ctx.InstallInTestcases() {
+ installDir = android.PathForModuleInstall(ctx, as.BaseModuleName(), ctx.DeviceConfig().DeviceArch())
+ } else {
+ installDir = android.PathForModuleInstall(ctx, "app", as.BaseModuleName())
+ }
+ ctx.InstallFile(installDir, as.masterFile", as.packedOutput)
+ */
+}
+
+// android_app_set extracts a set of APKs based on the target device
+// configuration and installs this set as "split APKs".
+// The set will always contain `base-master.apk` and every APK built
+// to the target device. All density-specific APK will be included, too,
+// unless PRODUCT_APPT_PREBUILT_DPI is defined (should contain comma-sepearated
+// list of density names (LDPI, MDPI, HDPI, etc.)
+func AndroidApkSetFactory() android.Module {
+ module := &AndroidAppSet{}
+ module.AddProperties(&module.properties)
+ InitJavaModule(module, android.DeviceSupported)
+ android.InitSingleSourcePrebuiltModule(module, &module.properties, "Set")
+ return module
}
// AndroidManifest.xml merging
@@ -129,6 +251,9 @@ type overridableAppProperties struct {
// or an android_app_certificate module name in the form ":module".
Certificate *string
+ // Name of the signing certificate lineage file.
+ Lineage *string
+
// the package name of this app. The package name in the manifest file is used if one was not given.
Package_name *string
@@ -249,7 +374,10 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
// If the app builds against an Android SDK use the SDK variant of JNI dependencies
// unless jni_uses_platform_apis is set.
- if (usesSDK && !Bool(a.appProperties.Jni_uses_platform_apis)) ||
+ // Don't require the SDK variant for apps that are shipped on vendor, etc., as they already
+ // have stable APIs through the VNDK.
+ if (usesSDK && !a.RequiresStableAPIs(ctx) &&
+ !Bool(a.appProperties.Jni_uses_platform_apis)) ||
Bool(a.appProperties.Jni_uses_sdk_apis) {
variation = append(variation, blueprint.Variation{Mutator: "sdk", Variation: "sdk"})
}
@@ -286,19 +414,47 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
- if Bool(a.appProperties.Updatable) {
+ if a.Updatable() {
if !a.sdkVersion().stable() {
ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.sdkVersion())
}
if String(a.deviceProperties.Min_sdk_version) == "" {
ctx.PropertyErrorf("updatable", "updatable apps must set min_sdk_version.")
}
+ if minSdkVersion, err := a.minSdkVersion().effectiveVersion(ctx); err == nil {
+ a.checkJniLibsSdkVersion(ctx, minSdkVersion)
+ } else {
+ ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
+ }
}
a.checkPlatformAPI(ctx)
a.checkSdkVersions(ctx)
}
+// 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 linkType 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 sdkVersion) {
+ // 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) {
+ if !IsJniDepTag(ctx.OtherModuleDependencyTag(m)) {
+ return
+ }
+ dep, _ := m.(*cc.Module)
+ jniSdkVersion, err := android.ApiStrToNum(ctx, dep.SdkVersion())
+ if err != nil || int(minSdkVersion) < 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())
+ return
+ }
+
+ })
+}
+
// Returns true if the native libraries should be stored in the APK uncompressed and the
// extractNativeLibs application flag should be set to false in the manifest.
func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool {
@@ -412,16 +568,17 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
installDir = filepath.Join("app", a.installApkName)
}
a.dexpreopter.installPath = android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk")
- a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
-
+ if a.deviceProperties.Uncompress_dex == nil {
+ // If the value was not force-set by the user, use reasonable default based on the module.
+ a.deviceProperties.Uncompress_dex = proptools.BoolPtr(a.shouldUncompressDex(ctx))
+ }
+ a.dexpreopter.uncompressedDex = *a.deviceProperties.Uncompress_dex
a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
a.dexpreopter.usesLibs = a.usesLibrary.usesLibraryProperties.Uses_libs
a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx)
a.dexpreopter.libraryPaths = a.usesLibrary.usesLibraryPaths(ctx)
a.dexpreopter.manifestFile = a.mergedManifestFile
- a.deviceProperties.UncompressDex = a.dexpreopter.uncompressedDex
-
if ctx.ModuleName() != "framework-res" {
a.Module.compile(ctx, a.aaptSrcJar)
}
@@ -584,7 +741,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
dexJarFile := a.dexBuildActions(ctx)
- jniLibs, certificateDeps := collectAppDeps(ctx, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
+ jniLibs, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
jniJarFile := a.jniBuildActions(jniLibs, ctx)
if ctx.Failed() {
@@ -596,13 +753,17 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
// Build a final signed app package.
packageFile := android.PathForModuleOut(ctx, a.installApkName+".apk")
- CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps)
+ var lineageFile android.Path
+ if lineage := String(a.overridableAppProperties.Lineage); lineage != "" {
+ lineageFile = android.PathForModuleSrc(ctx, lineage)
+ }
+ CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, lineageFile)
a.outputFile = packageFile
for _, split := range a.aapt.splits {
// Sign the split APKs
packageFile := android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk")
- CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps)
+ CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, lineageFile)
a.extraOutputFiles = append(a.extraOutputFiles, packageFile)
}
@@ -622,12 +783,25 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
a.buildAppDependencyInfo(ctx)
}
-func collectAppDeps(ctx android.ModuleContext, shouldCollectRecursiveNativeDeps bool,
+type appDepsInterface interface {
+ sdkVersion() sdkSpec
+ minSdkVersion() sdkSpec
+ RequiresStableAPIs(ctx android.BaseModuleContext) bool
+}
+
+func collectAppDeps(ctx android.ModuleContext, app appDepsInterface,
+ shouldCollectRecursiveNativeDeps bool,
checkNativeSdkVersion bool) ([]jniLib, []Certificate) {
+
var jniLibs []jniLib
var certificates []Certificate
seenModulePaths := make(map[string]bool)
+ if checkNativeSdkVersion {
+ checkNativeSdkVersion = app.sdkVersion().specified() &&
+ app.sdkVersion().kind != sdkCorePlatform && !app.RequiresStableAPIs(ctx)
+ }
+
ctx.WalkDeps(func(module android.Module, parent android.Module) bool {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
@@ -645,16 +819,9 @@ func collectAppDeps(ctx android.ModuleContext, shouldCollectRecursiveNativeDeps
}
seenModulePaths[path.String()] = true
- if checkNativeSdkVersion {
- if app, ok := ctx.Module().(interface{ sdkVersion() sdkSpec }); ok {
- if app.sdkVersion().specified() &&
- app.sdkVersion().kind != sdkCorePlatform &&
- 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() {
@@ -731,6 +898,10 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) {
a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(), depsInfo)
}
+func (a *AndroidApp) Updatable() bool {
+ return Bool(a.appProperties.Updatable) || a.ApexModuleBase.Updatable()
+}
+
func (a *AndroidApp) getCertString(ctx android.BaseModuleContext) string {
certificate, overridden := ctx.DeviceConfig().OverrideCertificateFor(ctx.ModuleName())
if overridden {
@@ -835,6 +1006,7 @@ func (a *AndroidTest) InstallInTestcases() bool {
}
func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ var configs []tradefed.Config
if a.appTestProperties.Instrumentation_target_package != nil {
a.additionalAaptFlags = append(a.additionalAaptFlags,
"--rename-instrumentation-target-package "+*a.appTestProperties.Instrumentation_target_package)
@@ -847,8 +1019,12 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
a.generateAndroidBuildActions(ctx)
+ for _, module := range a.testProperties.Test_mainline_modules {
+ configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: "mainline-param", Value: module})
+ }
+
testConfig := tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config,
- a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites, a.testProperties.Auto_gen_config)
+ a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites, a.testProperties.Auto_gen_config, configs)
a.testConfig = a.FixTestConfig(ctx, testConfig)
a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
}
@@ -1086,6 +1262,8 @@ type AndroidAppImport struct {
usesLibrary usesLibrary
+ preprocessed bool
+
installPath android.InstallPath
}
@@ -1101,6 +1279,9 @@ type AndroidAppImportProperties struct {
// be set for presigned modules.
Presigned *bool
+ // Name of the signing certificate lineage file.
+ Lineage *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
@@ -1175,7 +1356,7 @@ func (a *AndroidAppImport) uncompressEmbeddedJniLibs(
ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
// Test apps don't need their JNI libraries stored uncompressed. As a matter of fact, messing
// with them may invalidate pre-existing signature data.
- if ctx.InstallInTestcases() && Bool(a.properties.Presigned) {
+ if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || a.preprocessed) {
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
Output: outputPath,
@@ -1196,7 +1377,7 @@ func (a *AndroidAppImport) uncompressEmbeddedJniLibs(
// Returns whether this module should have the dex file stored uncompressed in the APK.
func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool {
- if ctx.Config().UnbundledBuild() {
+ if ctx.Config().UnbundledBuild() || a.preprocessed {
return false
}
@@ -1244,7 +1425,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext
ctx.ModuleErrorf("One and only one of certficate, presigned, and default_dev_cert properties must be set")
}
- _, certificates := collectAppDeps(ctx, false, false)
+ _, certificates := collectAppDeps(ctx, a, false, false)
// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
// TODO: LOCAL_PACKAGE_SPLITS
@@ -1288,9 +1469,13 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext
apkFilename := proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".apk")
- // Sign or align the package
// TODO: Handle EXTERNAL
- if !Bool(a.properties.Presigned) {
+
+ // Sign or align the package if package has not been preprocessed
+ if a.preprocessed {
+ a.outputFile = srcApk
+ a.certificate = presignedCertificate
+ } else if !Bool(a.properties.Presigned) {
// If the certificate property is empty at this point, default_dev_cert must be set to true.
// Which makes processMainCert's behavior for the empty cert string WAI.
certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx)
@@ -1299,7 +1484,11 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext
}
a.certificate = certificates[0]
signed := android.PathForModuleOut(ctx, "signed", apkFilename)
- SignAppPackage(ctx, signed, dexOutput, certificates)
+ var lineageFile android.Path
+ if lineage := String(a.properties.Lineage); lineage != "" {
+ lineageFile = android.PathForModuleSrc(ctx, lineage)
+ }
+ SignAppPackage(ctx, signed, dexOutput, certificates, lineageFile)
a.outputFile = signed
} else {
alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename)
@@ -1370,6 +1559,14 @@ func (a *AndroidAppImport) DepIsInSameApex(ctx android.BaseModuleContext, dep an
return false
}
+func (a *AndroidAppImport) sdkVersion() sdkSpec {
+ return sdkSpecFrom("")
+}
+
+func (a *AndroidAppImport) minSdkVersion() sdkSpec {
+ return sdkSpecFrom("")
+}
+
func createVariantGroupType(variants []string, variantGroupName string) reflect.Type {
props := reflect.TypeOf((*AndroidAppImportProperties)(nil))
@@ -1417,21 +1614,31 @@ func AndroidAppImportFactory() android.Module {
})
android.InitApexModule(module)
- InitJavaModule(module, android.DeviceSupported)
+ android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk")
return module
}
+type androidTestImportProperties struct {
+ // Whether the prebuilt apk can be installed without additional processing. Default is false.
+ Preprocessed *bool
+}
+
type AndroidTestImport struct {
AndroidAppImport
testProperties testProperties
+ testImportProperties androidTestImportProperties
+
data android.Paths
}
func (a *AndroidTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ a.preprocessed = Bool(a.testImportProperties.Preprocessed)
+
a.generateAndroidBuildActions(ctx)
a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
@@ -1449,6 +1656,7 @@ func AndroidTestImportFactory() android.Module {
module.AddProperties(&module.dexpreoptProperties)
module.AddProperties(&module.usesLibrary.usesLibraryProperties)
module.AddProperties(&module.testProperties)
+ module.AddProperties(&module.testImportProperties)
module.populateAllVariantStructs()
android.AddLoadHook(module, func(ctx android.LoadHookContext) {
module.processVariants(ctx)
@@ -1484,6 +1692,9 @@ type RuntimeResourceOverlayProperties struct {
// module name in the form ":module".
Certificate *string
+ // Name of the signing certificate lineage file.
+ Lineage *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
@@ -1555,10 +1766,14 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC
r.aapt.buildActions(ctx, r, aaptLinkFlags...)
// Sign the built package
- _, certificates := collectAppDeps(ctx, false, false)
+ _, certificates := collectAppDeps(ctx, r, false, false)
certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx)
signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk")
- SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates)
+ var lineageFile android.Path
+ if lineage := String(r.properties.Lineage); lineage != "" {
+ lineageFile = android.PathForModuleSrc(ctx, lineage)
+ }
+ SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, lineageFile)
r.certificate = certificates[0]
r.outputFile = signed
@@ -1648,6 +1863,7 @@ func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, hasFrameworkLibs
"org.apache.http.legacy",
"android.hidl.base-V1.0-java",
"android.hidl.manager-V1.0-java")
+ ctx.AddVariationDependencies(nil, usesLibTag, optionalUsesLibs...)
}
}
}
diff --git a/java/app_builder.go b/java/app_builder.go
index 5e7fbe6de..014bd54f1 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -26,16 +26,23 @@ import (
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/remoteexec"
)
var (
- Signapk = pctx.AndroidStaticRule("signapk",
+ Signapk, SignapkRE = remoteexec.StaticRules(pctx, "signapk",
blueprint.RuleParams{
- Command: `${config.JavaCmd} ${config.JavaVmFlags} -Djava.library.path=$$(dirname ${config.SignapkJniLibrary}) ` +
+ Command: `$reTemplate${config.JavaCmd} ${config.JavaVmFlags} -Djava.library.path=$$(dirname ${config.SignapkJniLibrary}) ` +
`-jar ${config.SignapkCmd} $flags $certificates $in $out`,
CommandDeps: []string{"${config.SignapkCmd}", "${config.SignapkJniLibrary}"},
},
- "flags", "certificates")
+ &remoteexec.REParams{Labels: map[string]string{"type": "tool", "name": "signapk"},
+ ExecStrategy: "${config.RESignApkExecStrategy}",
+ Inputs: []string{"${config.SignapkCmd}", "$in", "$$(dirname ${config.SignapkJniLibrary})", "$implicits"},
+ OutputFiles: []string{"$outCommaList"},
+ ToolchainInputs: []string{"${config.JavaCmd}"},
+ Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+ }, []string{"flags", "certificates"}, []string{"implicits", "outCommaList"})
)
var combineApk = pctx.AndroidStaticRule("combineApk",
@@ -45,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) {
+ packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, lineageFile android.Path) {
unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk"
unsignedApk := android.PathForModuleOut(ctx, unsignedApkName)
@@ -66,10 +73,10 @@ func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.Writa
Implicits: deps,
})
- SignAppPackage(ctx, outputFile, unsignedApk, certificates)
+ SignAppPackage(ctx, outputFile, unsignedApk, certificates, lineageFile)
}
-func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate) {
+func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate, lineageFile android.Path) {
var certificateArgs []string
var deps android.Paths
@@ -78,15 +85,30 @@ func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, u
deps = append(deps, c.Pem, c.Key)
}
+ outputFiles := android.WritablePaths{signedApk}
+ var flags []string
+ if lineageFile != nil {
+ flags = append(flags, "--lineage", lineageFile.String())
+ deps = append(deps, lineageFile)
+ }
+
+ rule := Signapk
+ args := map[string]string{
+ "certificates": strings.Join(certificateArgs, " "),
+ "flags": strings.Join(flags, " "),
+ }
+ if ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
+ rule = SignapkRE
+ args["implicits"] = strings.Join(deps.Strings(), ",")
+ args["outCommaList"] = strings.Join(outputFiles.Strings(), ",")
+ }
ctx.Build(pctx, android.BuildParams{
- Rule: Signapk,
+ Rule: rule,
Description: "signapk",
- Output: signedApk,
+ Outputs: outputFiles,
Input: unsignedApk,
Implicits: deps,
- Args: map[string]string{
- "certificates": strings.Join(certificateArgs, " "),
- },
+ Args: args,
})
}
@@ -210,14 +232,20 @@ func TransformJniLibsToJar(ctx android.ModuleContext, outputFile android.Writabl
"-f", j.path.String())
}
+ rule := zip
+ args := map[string]string{
+ "jarArgs": strings.Join(proptools.NinjaAndShellEscapeList(jarArgs), " "),
+ }
+ if ctx.Config().IsEnvTrue("RBE_ZIP") {
+ rule = zipRE
+ args["implicits"] = strings.Join(deps.Strings(), ",")
+ }
ctx.Build(pctx, android.BuildParams{
- Rule: zip,
+ Rule: rule,
Description: "zip jni libs",
Output: outputFile,
Implicits: deps,
- Args: map[string]string{
- "jarArgs": strings.Join(proptools.NinjaAndShellEscapeList(jarArgs), " "),
- },
+ Args: args,
})
}
diff --git a/java/app_test.go b/java/app_test.go
index 4bcfa5a81..eb583bea6 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -141,6 +141,94 @@ func TestAppSplits(t *testing.T) {
}
}
+func TestAndroidAppSet(t *testing.T) {
+ ctx, config := testJava(t, `
+ android_app_set {
+ name: "foo",
+ set: "prebuilts/apks/app.apks",
+ prerelease: true,
+ }`)
+ module := ctx.ModuleForTests("foo", "android_common")
+ const packedSplitApks = "extracted.zip"
+ params := module.Output(packedSplitApks)
+ if params.Rule == nil {
+ t.Errorf("expected output %s is missing", packedSplitApks)
+ }
+ if s := params.Args["allow-prereleased"]; s != "true" {
+ t.Errorf("wrong allow-prereleased value: '%s', expected 'true'", s)
+ }
+ mkEntries := android.AndroidMkEntriesForTest(t, config, "", module.Module())[0]
+ actualMaster := mkEntries.EntryMap["LOCAL_APK_SET_MASTER_FILE"]
+ expectedMaster := []string{"foo.apk"}
+ if !reflect.DeepEqual(actualMaster, expectedMaster) {
+ t.Errorf("Unexpected LOCAL_APK_SET_MASTER_FILE value: '%s', expected: '%s',",
+ actualMaster, expectedMaster)
+ }
+}
+
+func TestAndroidAppSet_Variants(t *testing.T) {
+ bp := `
+ android_app_set {
+ name: "foo",
+ set: "prebuilts/apks/app.apks",
+ }`
+ testCases := []struct {
+ name string
+ deviceArch *string
+ deviceSecondaryArch *string
+ aaptPrebuiltDPI []string
+ sdkVersion int
+ expected map[string]string
+ }{
+ {
+ name: "One",
+ deviceArch: proptools.StringPtr("x86"),
+ aaptPrebuiltDPI: []string{"ldpi", "xxhdpi"},
+ sdkVersion: 29,
+ expected: map[string]string{
+ "abis": "X86",
+ "allow-prereleased": "false",
+ "screen-densities": "LDPI,XXHDPI",
+ "sdk-version": "29",
+ "stem": "foo",
+ },
+ },
+ {
+ name: "Two",
+ deviceArch: proptools.StringPtr("x86_64"),
+ deviceSecondaryArch: proptools.StringPtr("x86"),
+ aaptPrebuiltDPI: nil,
+ sdkVersion: 30,
+ expected: map[string]string{
+ "abis": "X86_64,X86",
+ "allow-prereleased": "false",
+ "screen-densities": "all",
+ "sdk-version": "30",
+ "stem": "foo",
+ },
+ },
+ }
+
+ for _, test := range testCases {
+ config := testAppConfig(nil, bp, nil)
+ config.TestProductVariables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI
+ config.TestProductVariables.Platform_sdk_version = &test.sdkVersion
+ config.TestProductVariables.DeviceArch = test.deviceArch
+ config.TestProductVariables.DeviceSecondaryArch = test.deviceSecondaryArch
+ ctx := testContext()
+ run(t, ctx, config)
+ module := ctx.ModuleForTests("foo", "android_common")
+ const packedSplitApks = "extracted.zip"
+ params := module.Output(packedSplitApks)
+ for k, v := range test.expected {
+ if actual := params.Args[k]; actual != v {
+ t.Errorf("%s: bad build arg value for '%s': '%s', expected '%s'",
+ test.name, k, actual, v)
+ }
+ }
+ }
+}
+
func TestPlatformAPIs(t *testing.T) {
testJava(t, `
android_app {
@@ -385,6 +473,127 @@ func TestUpdatableApps(t *testing.T) {
}
}
+func TestUpdatableApps_JniLibsShouldShouldSupportMinSdkVersion(t *testing.T) {
+ testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ updatable: true,
+ sdk_version: "current",
+ min_sdk_version: "current",
+ jni_libs: ["libjni"],
+ }
+
+ cc_library {
+ name: "libjni",
+ stl: "none",
+ system_shared_libs: [],
+ sdk_version: "current",
+ }
+ `)
+}
+
+func TestUpdatableApps_JniLibShouldBeBuiltAgainstMinSdkVersion(t *testing.T) {
+ bp := cc.GatherRequiredDepsForTest(android.Android) + `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ updatable: true,
+ sdk_version: "current",
+ min_sdk_version: "29",
+ jni_libs: ["libjni"],
+ }
+
+ cc_library {
+ name: "libjni",
+ stl: "none",
+ system_shared_libs: [],
+ sdk_version: "29",
+ }
+
+ ndk_prebuilt_object {
+ name: "ndk_crtbegin_so.29",
+ sdk_version: "29",
+ }
+
+ ndk_prebuilt_object {
+ name: "ndk_crtend_so.29",
+ sdk_version: "29",
+ }
+ `
+ fs := map[string][]byte{
+ "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtbegin_so.o": nil,
+ "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtend_so.o": nil,
+ "prebuilts/ndk/current/platforms/android-29/arch-arm/usr/lib/crtbegin_so.o": nil,
+ "prebuilts/ndk/current/platforms/android-29/arch-arm/usr/lib/crtend_so.o": nil,
+ }
+
+ ctx, _ := testJavaWithConfig(t, testConfig(nil, bp, fs))
+
+ inputs := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared").Description("link").Implicits
+ var crtbeginFound, crtendFound bool
+ for _, input := range inputs {
+ switch input.String() {
+ case "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtbegin_so.o":
+ crtbeginFound = true
+ case "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtend_so.o":
+ crtendFound = true
+ }
+ }
+ if !crtbeginFound || !crtendFound {
+ t.Error("should link with ndk_crtbegin_so.29 and ndk_crtend_so.29")
+ }
+}
+
+func TestUpdatableApps_ErrorIfJniLibDoesntSupportMinSdkVersion(t *testing.T) {
+ bp := cc.GatherRequiredDepsForTest(android.Android) + `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ updatable: true,
+ sdk_version: "current",
+ min_sdk_version: "29", // this APK should support 29
+ jni_libs: ["libjni"],
+ }
+
+ cc_library {
+ name: "libjni",
+ stl: "none",
+ sdk_version: "current",
+ }
+ `
+ testJavaError(t, `"libjni" .*: sdk_version\(current\) is higher than min_sdk_version\(29\)`, bp)
+}
+
+func TestUpdatableApps_ErrorIfDepSdkVersionIsHigher(t *testing.T) {
+ bp := cc.GatherRequiredDepsForTest(android.Android) + `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ updatable: true,
+ sdk_version: "current",
+ min_sdk_version: "29", // this APK should support 29
+ jni_libs: ["libjni"],
+ }
+
+ cc_library {
+ name: "libjni",
+ stl: "none",
+ shared_libs: ["libbar"],
+ system_shared_libs: [],
+ sdk_version: "27",
+ }
+
+ cc_library {
+ name: "libbar",
+ stl: "none",
+ system_shared_libs: [],
+ sdk_version: "current",
+ }
+ `
+ testJavaError(t, `"libjni" .*: links "libbar" built against newer API version "current"`, bp)
+}
+
func TestResourceDirs(t *testing.T) {
testCases := []struct {
name string
@@ -1144,25 +1353,44 @@ func TestJNISDK(t *testing.T) {
platform_apis: true,
jni_uses_sdk_apis: true,
}
+
+ cc_library {
+ name: "libvendorjni",
+ system_shared_libs: [],
+ stl: "none",
+ vendor: true,
+ }
+
+ android_test {
+ name: "app_vendor",
+ jni_libs: ["libvendorjni"],
+ sdk_version: "current",
+ vendor: true,
+ }
`)
testCases := []struct {
- name string
- sdkJNI bool
+ name string
+ sdkJNI bool
+ vendorJNI bool
}{
- {"app_platform", false},
- {"app_sdk", true},
- {"app_force_platform", false},
- {"app_force_sdk", true},
+ {name: "app_platform"},
+ {name: "app_sdk", sdkJNI: true},
+ {name: "app_force_platform"},
+ {name: "app_force_sdk", sdkJNI: true},
+ {name: "app_vendor", vendorJNI: true},
}
+ platformJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_shared").
+ Output("libjni.so").Output.String()
+ sdkJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared").
+ Output("libjni.so").Output.String()
+ vendorJNI := ctx.ModuleForTests("libvendorjni", "android_arm64_armv8-a_shared").
+ Output("libvendorjni.so").Output.String()
+
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
app := ctx.ModuleForTests(test.name, "android_common")
- platformJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_shared").
- Output("libjni.so").Output.String()
- sdkJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared").
- Output("libjni.so").Output.String()
jniLibZip := app.MaybeOutput("jnilibs.zip")
if len(jniLibZip.Implicits) != 1 {
@@ -1174,6 +1402,10 @@ func TestJNISDK(t *testing.T) {
if gotJNI != sdkJNI {
t.Errorf("expected SDK JNI library %q, got %q", sdkJNI, gotJNI)
}
+ } else if test.vendorJNI {
+ if gotJNI != vendorJNI {
+ t.Errorf("expected platform JNI library %q, got %q", vendorJNI, gotJNI)
+ }
} else {
if gotJNI != platformJNI {
t.Errorf("expected platform JNI library %q, got %q", platformJNI, gotJNI)
@@ -1209,7 +1441,8 @@ func TestCertificates(t *testing.T) {
name string
bp string
certificateOverride string
- expected string
+ expectedLineage string
+ expectedCertificate string
}{
{
name: "default",
@@ -1221,7 +1454,8 @@ func TestCertificates(t *testing.T) {
}
`,
certificateOverride: "",
- expected: "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8",
+ expectedLineage: "",
+ expectedCertificate: "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8",
},
{
name: "module certificate property",
@@ -1239,7 +1473,8 @@ func TestCertificates(t *testing.T) {
}
`,
certificateOverride: "",
- expected: "cert/new_cert.x509.pem cert/new_cert.pk8",
+ expectedLineage: "",
+ expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
},
{
name: "path certificate property",
@@ -1252,7 +1487,8 @@ func TestCertificates(t *testing.T) {
}
`,
certificateOverride: "",
- expected: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ expectedLineage: "",
+ expectedCertificate: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
},
{
name: "certificate overrides",
@@ -1270,7 +1506,28 @@ func TestCertificates(t *testing.T) {
}
`,
certificateOverride: "foo:new_certificate",
- expected: "cert/new_cert.x509.pem cert/new_cert.pk8",
+ expectedLineage: "",
+ expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
+ },
+ {
+ name: "certificate lineage",
+ bp: `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ certificate: ":new_certificate",
+ lineage: "lineage.bin",
+ sdk_version: "current",
+ }
+
+ android_app_certificate {
+ name: "new_certificate",
+ certificate: "cert/new_cert",
+ }
+ `,
+ certificateOverride: "",
+ expectedLineage: "--lineage lineage.bin",
+ expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
},
}
@@ -1286,9 +1543,14 @@ func TestCertificates(t *testing.T) {
foo := ctx.ModuleForTests("foo", "android_common")
signapk := foo.Output("foo.apk")
- signFlags := signapk.Args["certificates"]
- if test.expected != signFlags {
- t.Errorf("Incorrect signing flags, expected: %q, got: %q", test.expected, signFlags)
+ signCertificateFlags := signapk.Args["certificates"]
+ if test.expectedCertificate != signCertificateFlags {
+ t.Errorf("Incorrect signing flags, expected: %q, got: %q", test.expectedCertificate, signCertificateFlags)
+ }
+
+ signFlags := signapk.Args["flags"]
+ if test.expectedLineage != signFlags {
+ t.Errorf("Incorrect signing flags, expected: %q, got: %q", test.expectedLineage, signFlags)
}
})
}
@@ -1402,6 +1664,7 @@ func TestOverrideAndroidApp(t *testing.T) {
name: "bar",
base: "foo",
certificate: ":new_certificate",
+ lineage: "lineage.bin",
logging_parent: "bah",
}
@@ -1422,7 +1685,8 @@ func TestOverrideAndroidApp(t *testing.T) {
variantName string
apkName string
apkPath string
- signFlag string
+ certFlag string
+ lineageFlag string
overrides []string
aaptFlag string
logging_parent string
@@ -1431,7 +1695,8 @@ func TestOverrideAndroidApp(t *testing.T) {
moduleName: "foo",
variantName: "android_common",
apkPath: "/target/product/test_device/system/app/foo/foo.apk",
- signFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ lineageFlag: "",
overrides: []string{"qux"},
aaptFlag: "",
logging_parent: "",
@@ -1440,7 +1705,8 @@ func TestOverrideAndroidApp(t *testing.T) {
moduleName: "bar",
variantName: "android_common_bar",
apkPath: "/target/product/test_device/system/app/bar/bar.apk",
- signFlag: "cert/new_cert.x509.pem cert/new_cert.pk8",
+ certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8",
+ lineageFlag: "--lineage lineage.bin",
overrides: []string{"qux", "foo"},
aaptFlag: "",
logging_parent: "bah",
@@ -1449,7 +1715,8 @@ func TestOverrideAndroidApp(t *testing.T) {
moduleName: "baz",
variantName: "android_common_baz",
apkPath: "/target/product/test_device/system/app/baz/baz.apk",
- signFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ lineageFlag: "",
overrides: []string{"qux", "foo"},
aaptFlag: "--rename-manifest-package org.dandroid.bp",
logging_parent: "",
@@ -1474,9 +1741,15 @@ func TestOverrideAndroidApp(t *testing.T) {
// Check the certificate paths
signapk := variant.Output(expected.moduleName + ".apk")
- signFlag := signapk.Args["certificates"]
- if expected.signFlag != signFlag {
- t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected.signFlag, signFlag)
+ certFlag := signapk.Args["certificates"]
+ if expected.certFlag != certFlag {
+ t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected.certFlag, certFlag)
+ }
+
+ // Check the lineage flags
+ lineageFlag := signapk.Args["flags"]
+ if expected.lineageFlag != lineageFlag {
+ t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected.lineageFlag, lineageFlag)
}
// Check if the overrides field values are correctly aggregated.
@@ -1798,6 +2071,27 @@ func TestAndroidAppImport_Presigned(t *testing.T) {
}
}
+func TestAndroidAppImport_SigningLineage(t *testing.T) {
+ ctx, _ := testJava(t, `
+ android_app_import {
+ name: "foo",
+ apk: "prebuilts/apk/app.apk",
+ certificate: "platform",
+ lineage: "lineage.bin",
+ }
+ `)
+
+ variant := ctx.ModuleForTests("foo", "android_common")
+
+ // Check cert signing lineage flag.
+ signedApk := variant.Output("signed/foo.apk")
+ signingFlag := signedApk.Args["flags"]
+ expected := "--lineage lineage.bin"
+ if expected != signingFlag {
+ t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
+ }
+}
+
func TestAndroidAppImport_DefaultDevCert(t *testing.T) {
ctx, _ := testJava(t, `
android_app_import {
@@ -2075,6 +2369,45 @@ func TestAndroidTestImport_NoJinUncompressForPresigned(t *testing.T) {
if jniRule != android.Cp.String() {
t.Errorf("Unexpected JNI uncompress rule: " + jniRule)
}
+ if variant.MaybeOutput("zip-aligned/foo_presigned.apk").Rule == nil {
+ t.Errorf("Presigned test apk should be aligned")
+ }
+}
+
+func TestAndroidTestImport_Preprocessed(t *testing.T) {
+ ctx, _ := testJava(t, `
+ android_test_import {
+ name: "foo",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ preprocessed: true,
+ }
+
+ android_test_import {
+ name: "foo_cert",
+ apk: "prebuilts/apk/app.apk",
+ certificate: "cert/new_cert",
+ preprocessed: true,
+ }
+ `)
+
+ testModules := []string{"foo", "foo_cert"}
+ for _, m := range testModules {
+ apkName := m + ".apk"
+ variant := ctx.ModuleForTests(m, "android_common")
+ jniRule := variant.Output("jnis-uncompressed/" + apkName).BuildParams.Rule.String()
+ if jniRule != android.Cp.String() {
+ t.Errorf("Unexpected JNI uncompress rule: " + jniRule)
+ }
+
+ // Make sure signing and aligning were skipped.
+ if variant.MaybeOutput("signed/"+apkName).Rule != nil {
+ t.Errorf("signing rule shouldn't be included for preprocessed.")
+ }
+ if variant.MaybeOutput("zip-aligned/"+apkName).Rule != nil {
+ t.Errorf("aligning rule shouldn't be for preprocessed")
+ }
+ }
}
func TestStl(t *testing.T) {
@@ -2150,6 +2483,20 @@ func TestUsesLibraries(t *testing.T) {
}
java_sdk_library {
+ name: "qux",
+ srcs: ["a.java"],
+ api_packages: ["qux"],
+ sdk_version: "current",
+ }
+
+ java_sdk_library {
+ name: "quuz",
+ srcs: ["a.java"],
+ api_packages: ["quuz"],
+ sdk_version: "current",
+ }
+
+ java_sdk_library {
name: "bar",
srcs: ["a.java"],
api_packages: ["bar"],
@@ -2159,6 +2506,7 @@ func TestUsesLibraries(t *testing.T) {
android_app {
name: "app",
srcs: ["a.java"],
+ libs: ["qux", "quuz.stubs"],
uses_libs: ["foo"],
sdk_version: "current",
optional_uses_libs: [
@@ -2189,6 +2537,15 @@ func TestUsesLibraries(t *testing.T) {
app := ctx.ModuleForTests("app", "android_common")
prebuilt := ctx.ModuleForTests("prebuilt", "android_common")
+ // Test that implicit dependencies on java_sdk_library instances are passed to the manifest.
+ manifestFixerArgs := app.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
+ if w := "--uses-library qux"; !strings.Contains(manifestFixerArgs, w) {
+ t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs)
+ }
+ if w := "--uses-library quuz"; !strings.Contains(manifestFixerArgs, w) {
+ t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs)
+ }
+
// Test that all libraries are verified
cmd := app.Rule("verify_uses_libraries").RuleParams.Command
if w := "--uses-library foo"; !strings.Contains(cmd, w) {
@@ -2449,6 +2806,32 @@ func TestUncompressDex(t *testing.T) {
uncompressedPlatform: true,
uncompressedUnbundled: true,
},
+ {
+ name: "normal_uncompress_dex_true",
+ bp: `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ uncompress_dex: true,
+ }
+ `,
+ uncompressedPlatform: true,
+ uncompressedUnbundled: true,
+ },
+ {
+ name: "normal_uncompress_dex_false",
+ bp: `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ uncompress_dex: false,
+ }
+ `,
+ uncompressedPlatform: false,
+ uncompressedUnbundled: false,
+ },
}
test := func(t *testing.T, bp string, want bool, unbundled bool) {
@@ -2512,6 +2895,7 @@ func TestRuntimeResourceOverlay(t *testing.T) {
runtime_resource_overlay {
name: "foo",
certificate: "platform",
+ lineage: "lineage.bin",
product_specific: true,
static_libs: ["bar"],
resource_libs: ["baz"],
@@ -2566,6 +2950,11 @@ func TestRuntimeResourceOverlay(t *testing.T) {
// Check cert signing flag.
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)
+ }
signingFlag := signedApk.Args["certificates"]
expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8"
if expected != signingFlag {
diff --git a/java/builder.go b/java/builder.go
index 3a4a10d3c..a27e5c390 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -40,17 +40,17 @@ var (
// (if the rule produces .class files) or a .srcjar file (if the rule produces .java files).
// .srcjar files are unzipped into a temporary directory when compiled with javac.
// TODO(b/143658984): goma can't handle the --system argument to javac.
- javac, javacRE = remoteexec.StaticRules(pctx, "javac",
+ javac, javacRE = remoteexec.MultiCommandStaticRules(pctx, "javac",
blueprint.RuleParams{
Command: `rm -rf "$outDir" "$annoDir" "$srcJarDir" && mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
`(if [ -s $srcJarDir/list ] || [ -s $out.rsp ] ; then ` +
- `${config.SoongJavacWrapper} $reTemplate${config.JavacCmd} ` +
+ `${config.SoongJavacWrapper} $javaTemplate${config.JavacCmd} ` +
`${config.JavacHeapFlags} ${config.JavacVmFlags} ${config.CommonJdkFlags} ` +
`$processorpath $processor $javacFlags $bootClasspath $classpath ` +
`-source $javaVersion -target $javaVersion ` +
`-d $outDir -s $annoDir @$out.rsp @$srcJarDir/list ; fi ) && ` +
- `${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir && ` +
+ `$zipTemplate${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir && ` +
`rm -rf "$srcJarDir"`,
CommandDeps: []string{
"${config.JavacCmd}",
@@ -60,10 +60,19 @@ var (
CommandOrderOnly: []string{"${config.SoongJavacWrapper}"},
Rspfile: "$out.rsp",
RspfileContent: "$in",
- }, &remoteexec.REParams{
- Labels: map[string]string{"type": "compile", "lang": "java", "compiler": "javac"},
- ExecStrategy: "${config.REJavacExecStrategy}",
- Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+ }, map[string]*remoteexec.REParams{
+ "$javaTemplate": &remoteexec.REParams{
+ Labels: map[string]string{"type": "compile", "lang": "java", "compiler": "javac"},
+ ExecStrategy: "${config.REJavacExecStrategy}",
+ Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+ },
+ "$zipTemplate": &remoteexec.REParams{
+ Labels: map[string]string{"type": "tool", "name": "soong_zip"},
+ Inputs: []string{"${config.SoongZipCmd}", "$outDir"},
+ OutputFiles: []string{"$out"},
+ ExecStrategy: "${config.REJavacExecStrategy}",
+ Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+ },
}, []string{"javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJars", "srcJarDir",
"outDir", "annoDir", "javaVersion"}, nil)
@@ -104,10 +113,22 @@ var (
"javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJars", "srcJarDir",
"outDir", "annoDir", "javaVersion")
- turbine = pctx.AndroidStaticRule("turbine",
+ extractMatchingApks = pctx.StaticRule(
+ "extractMatchingApks",
+ blueprint.RuleParams{
+ Command: `rm -rf "$out" && ` +
+ `${config.ExtractApksCmd} -o "${out}" -allow-prereleased=${allow-prereleased} ` +
+ `-sdk-version=${sdk-version} -abis=${abis} ` +
+ `--screen-densities=${screen-densities} --stem=${stem} ` +
+ `${in}`,
+ CommandDeps: []string{"${config.ExtractApksCmd}"},
+ },
+ "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem")
+
+ turbine, turbineRE = remoteexec.StaticRules(pctx, "turbine",
blueprint.RuleParams{
Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
- `${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.TurbineJar} --output $out.tmp ` +
+ `$reTemplate${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.TurbineJar} --output $out.tmp ` +
`--temp_dir "$outDir" --sources @$out.rsp --source_jars $srcJars ` +
`--javacopts ${config.CommonJdkFlags} ` +
`$javacFlags -source $javaVersion -target $javaVersion -- $bootClasspath $classpath && ` +
@@ -122,25 +143,45 @@ var (
RspfileContent: "$in",
Restat: true,
},
- "javacFlags", "bootClasspath", "classpath", "srcJars", "outDir", "javaVersion")
-
- jar = pctx.AndroidStaticRule("jar",
+ &remoteexec.REParams{Labels: map[string]string{"type": "tool", "name": "turbine"},
+ ExecStrategy: "${config.RETurbineExecStrategy}",
+ Inputs: []string{"${config.TurbineJar}", "${out}.rsp", "$implicits"},
+ RSPFile: "${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"})
+
+ jar, jarRE = remoteexec.StaticRules(pctx, "jar",
blueprint.RuleParams{
- Command: `${config.SoongZipCmd} -jar -o $out @$out.rsp`,
+ Command: `$reTemplate${config.SoongZipCmd} -jar -o $out @$out.rsp`,
CommandDeps: []string{"${config.SoongZipCmd}"},
Rspfile: "$out.rsp",
RspfileContent: "$jarArgs",
},
- "jarArgs")
+ &remoteexec.REParams{
+ ExecStrategy: "${config.REJarExecStrategy}",
+ Inputs: []string{"${config.SoongZipCmd}", "${out}.rsp"},
+ RSPFile: "${out}.rsp",
+ OutputFiles: []string{"$out"},
+ Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+ }, []string{"jarArgs"}, nil)
- zip = pctx.AndroidStaticRule("zip",
+ zip, zipRE = remoteexec.StaticRules(pctx, "zip",
blueprint.RuleParams{
Command: `${config.SoongZipCmd} -o $out @$out.rsp`,
CommandDeps: []string{"${config.SoongZipCmd}"},
Rspfile: "$out.rsp",
RspfileContent: "$jarArgs",
},
- "jarArgs")
+ &remoteexec.REParams{
+ ExecStrategy: "${config.REZipExecStrategy}",
+ Inputs: []string{"${config.SoongZipCmd}", "${out}.rsp", "$implicits"},
+ RSPFile: "${out}.rsp",
+ OutputFiles: []string{"$out"},
+ Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+ }, []string{"jarArgs"}, []string{"implicits"})
combineJar = pctx.AndroidStaticRule("combineJar",
blueprint.RuleParams{
@@ -334,20 +375,26 @@ func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android.
deps = append(deps, classpath...)
deps = append(deps, flags.processorPath...)
+ 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(),
+ }
+ if ctx.Config().IsEnvTrue("RBE_TURBINE") {
+ rule = turbineRE
+ args["implicits"] = strings.Join(deps.Strings(), ",")
+ }
ctx.Build(pctx, android.BuildParams{
- Rule: turbine,
+ Rule: rule,
Description: "turbine",
Output: outputFile,
Inputs: srcFiles,
Implicits: deps,
- 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(),
- },
+ Args: args,
})
}
@@ -431,8 +478,12 @@ func transformJavaToClasses(ctx android.ModuleContext, outputFile android.Writab
func TransformResourcesToJar(ctx android.ModuleContext, outputFile android.WritablePath,
jarArgs []string, deps android.Paths) {
+ rule := jar
+ if ctx.Config().IsEnvTrue("RBE_JAR") {
+ rule = jarRE
+ }
ctx.Build(pctx, android.BuildParams{
- Rule: jar,
+ Rule: rule,
Description: "jar",
Output: outputFile,
Implicits: deps,
diff --git a/java/config/config.go b/java/config/config.go
index c4f236346..edaed2a10 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -122,7 +122,7 @@ func init() {
pctx.HostBinToolVariable("D8Cmd", "d8")
pctx.HostBinToolVariable("R8Cmd", "r8-compat-proguard")
pctx.HostBinToolVariable("HiddenAPICmd", "hiddenapi")
-
+ pctx.HostBinToolVariable("ExtractApksCmd", "extract_apks")
pctx.VariableFunc("TurbineJar", func(ctx android.PackageVarContext) string {
turbine := "turbine.jar"
if ctx.Config().UnbundledBuild() {
@@ -148,6 +148,10 @@ func init() {
pctx.VariableFunc("REJavacExecStrategy", remoteexec.EnvOverrideFunc("RBE_JAVAC_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
pctx.VariableFunc("RED8ExecStrategy", remoteexec.EnvOverrideFunc("RBE_D8_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
pctx.VariableFunc("RER8ExecStrategy", remoteexec.EnvOverrideFunc("RBE_R8_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
+ pctx.VariableFunc("RETurbineExecStrategy", remoteexec.EnvOverrideFunc("RBE_TURBINE_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
+ pctx.VariableFunc("RESignApkExecStrategy", remoteexec.EnvOverrideFunc("RBE_SIGNAPK_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
+ pctx.VariableFunc("REJarExecStrategy", remoteexec.EnvOverrideFunc("RBE_JAR_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
+ pctx.VariableFunc("REZipExecStrategy", remoteexec.EnvOverrideFunc("RBE_ZIP_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
pctx.HostJavaToolVariable("JacocoCLIJar", "jacoco-cli.jar")
diff --git a/java/dex.go b/java/dex.go
index 27ec6ee41..9e61e95ad 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -18,53 +18,72 @@ import (
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
"android/soong/android"
"android/soong/remoteexec"
)
-var d8, d8RE = remoteexec.StaticRules(pctx, "d8",
+var d8, d8RE = remoteexec.MultiCommandStaticRules(pctx, "d8",
blueprint.RuleParams{
Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
- `$reTemplate${config.D8Cmd} ${config.DexFlags} --output $outDir $d8Flags $in && ` +
- `${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
+ `$d8Template${config.D8Cmd} ${config.DexFlags} --output $outDir $d8Flags $in && ` +
+ `$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`,
CommandDeps: []string{
"${config.D8Cmd}",
"${config.SoongZipCmd}",
"${config.MergeZipsCmd}",
},
- }, &remoteexec.REParams{
- Labels: map[string]string{"type": "compile", "compiler": "d8"},
- Inputs: []string{"${config.D8Jar}"},
- ExecStrategy: "${config.RED8ExecStrategy}",
- ToolchainInputs: []string{"${config.JavaCmd}"},
- Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+ }, map[string]*remoteexec.REParams{
+ "$d8Template": &remoteexec.REParams{
+ Labels: map[string]string{"type": "compile", "compiler": "d8"},
+ Inputs: []string{"${config.D8Jar}"},
+ ExecStrategy: "${config.RED8ExecStrategy}",
+ ToolchainInputs: []string{"${config.JavaCmd}"},
+ Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+ },
+ "$zipTemplate": &remoteexec.REParams{
+ Labels: map[string]string{"type": "tool", "name": "soong_zip"},
+ Inputs: []string{"${config.SoongZipCmd}", "$outDir"},
+ OutputFiles: []string{"$outDir/classes.dex.jar"},
+ ExecStrategy: "${config.RED8ExecStrategy}",
+ Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+ },
}, []string{"outDir", "d8Flags", "zipFlags"}, nil)
-var r8, r8RE = remoteexec.StaticRules(pctx, "r8",
+var r8, r8RE = remoteexec.MultiCommandStaticRules(pctx, "r8",
blueprint.RuleParams{
Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
`rm -f "$outDict" && ` +
- `$reTemplate${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` +
+ `$r8Template${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` +
`--force-proguard-compatibility ` +
`--no-data-resources ` +
`-printmapping $outDict ` +
`$r8Flags && ` +
`touch "$outDict" && ` +
- `${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
+ `$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`,
CommandDeps: []string{
"${config.R8Cmd}",
"${config.SoongZipCmd}",
"${config.MergeZipsCmd}",
},
- }, &remoteexec.REParams{
- Labels: map[string]string{"type": "compile", "compiler": "r8"},
- Inputs: []string{"$implicits", "${config.R8Jar}"},
- ExecStrategy: "${config.RER8ExecStrategy}",
- ToolchainInputs: []string{"${config.JavaCmd}"},
- Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+ }, map[string]*remoteexec.REParams{
+ "$r8Template": &remoteexec.REParams{
+ Labels: map[string]string{"type": "compile", "compiler": "r8"},
+ Inputs: []string{"$implicits", "${config.R8Jar}"},
+ ExecStrategy: "${config.RER8ExecStrategy}",
+ ToolchainInputs: []string{"${config.JavaCmd}"},
+ Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+ },
+ "$zipTemplate": &remoteexec.REParams{
+ Labels: map[string]string{"type": "tool", "name": "soong_zip"},
+ Inputs: []string{"${config.SoongZipCmd}", "$outDir"},
+ OutputFiles: []string{"$outDir/classes.dex.jar"},
+ ExecStrategy: "${config.RER8ExecStrategy}",
+ Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+ },
}, []string{"outDir", "outDict", "r8Flags", "zipFlags"}, []string{"implicits"})
func (j *Module) dexCommonFlags(ctx android.ModuleContext) []string {
@@ -188,7 +207,7 @@ func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags,
outDir := android.PathForModuleOut(ctx, "dex")
zipFlags := "--ignore_missing_files"
- if j.deviceProperties.UncompressDex {
+ if proptools.Bool(j.deviceProperties.Uncompress_dex) {
zipFlags += " -L 0"
}
@@ -235,7 +254,7 @@ func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags,
},
})
}
- if j.deviceProperties.UncompressDex {
+ if proptools.Bool(j.deviceProperties.Uncompress_dex) {
alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", jarName)
TransformZipAlign(ctx, alignedJavalibJar, javalibJar)
javalibJar = alignedJavalibJar
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index dffdc248f..ed61d4bd3 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -109,11 +109,11 @@ func (image bootImageConfig) getAnyAndroidVariant() *bootImageVariant {
return nil
}
-func (image bootImageConfig) moduleName(idx int) string {
+func (image bootImageConfig) moduleName(ctx android.PathContext, idx int) string {
// Dexpreopt on the boot class path produces multiple files. The first dex file
// is converted into 'name'.art (to match the legacy assumption that 'name'.art
// exists), and the rest are converted to 'name'-<jar>.art.
- _, m := android.SplitApexJarPair(image.modules[idx])
+ _, m := android.SplitApexJarPair(ctx, image.modules[idx])
name := image.stem
if idx != 0 || image.extends != nil {
name += "-" + stemOf(m)
@@ -121,9 +121,9 @@ func (image bootImageConfig) moduleName(idx int) string {
return name
}
-func (image bootImageConfig) firstModuleNameOrStem() string {
+func (image bootImageConfig) firstModuleNameOrStem(ctx android.PathContext) string {
if len(image.modules) > 0 {
- return image.moduleName(0)
+ return image.moduleName(ctx, 0)
} else {
return image.stem
}
@@ -132,7 +132,7 @@ func (image bootImageConfig) firstModuleNameOrStem() string {
func (image bootImageConfig) moduleFiles(ctx android.PathContext, dir android.OutputPath, exts ...string) android.OutputPaths {
ret := make(android.OutputPaths, 0, len(image.modules)*len(exts))
for i := range image.modules {
- name := image.moduleName(i)
+ name := image.moduleName(ctx, i)
for _, ext := range exts {
ret = append(ret, dir.Join(ctx, name+ext))
}
@@ -261,7 +261,7 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul
}
name := ctx.ModuleName(module)
- index := android.IndexList(name, android.GetJarsFromApexJarPairs(image.modules))
+ index := android.IndexList(name, android.GetJarsFromApexJarPairs(ctx, image.modules))
if index == -1 {
return -1, nil
}
@@ -314,7 +314,7 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootI
// Ensure all modules were converted to paths
for i := range bootDexJars {
if bootDexJars[i] == nil {
- _, m := android.SplitApexJarPair(image.modules[i])
+ _, m := android.SplitApexJarPair(ctx, image.modules[i])
if ctx.Config().AllowMissingDependencies() {
missingDeps = append(missingDeps, m)
bootDexJars[i] = android.PathForOutput(ctx, "missing")
@@ -614,15 +614,15 @@ func updatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConf
return ctx.Config().Once(updatableBcpPackagesRuleKey, func() interface{} {
global := dexpreopt.GetGlobalConfig(ctx)
- updatableModules := android.GetJarsFromApexJarPairs(global.UpdatableBootJars)
+ updatableModules := android.GetJarsFromApexJarPairs(ctx, global.UpdatableBootJars)
// Collect `permitted_packages` for updatable boot jars.
var updatablePackages []string
ctx.VisitAllModules(func(module android.Module) {
- if j, ok := module.(*Library); ok {
+ if j, ok := module.(PermittedPackagesForUpdatableBootJars); ok {
name := ctx.ModuleName(module)
if i := android.IndexList(name, updatableModules); i != -1 {
- pp := j.properties.Permitted_packages
+ pp := j.PermittedPackagesForUpdatableBootJars()
if len(pp) > 0 {
updatablePackages = append(updatablePackages, pp...)
} else {
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index 0946bf0a3..e9704dc2a 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -24,7 +24,7 @@ import (
"android/soong/dexpreopt"
)
-func TestDexpreoptBootJars(t *testing.T) {
+func testDexpreoptBoot(t *testing.T, ruleFile string, expectedInputs, expectedOutputs []string) {
bp := `
java_sdk_library {
name: "foo",
@@ -52,63 +52,84 @@ func TestDexpreoptBootJars(t *testing.T) {
dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
ctx := testContext()
-
RegisterDexpreoptBootJarsComponents(ctx)
-
run(t, ctx, config)
dexpreoptBootJars := ctx.SingletonForTests("dex_bootjars")
-
- bootArt := dexpreoptBootJars.Output("boot-foo.art")
-
- expectedInputs := []string{
- "dex_artjars/android/apex/com.android.art/javalib/arm64/boot.art",
- "dex_bootjars_input/foo.jar",
- "dex_bootjars_input/bar.jar",
- "dex_bootjars_input/baz.jar",
- }
+ rule := dexpreoptBootJars.Output(ruleFile)
for i := range expectedInputs {
expectedInputs[i] = filepath.Join(buildDir, "test_device", expectedInputs[i])
}
- inputs := bootArt.Implicits.Strings()
+ for i := range expectedOutputs {
+ expectedOutputs[i] = filepath.Join(buildDir, "test_device", expectedOutputs[i])
+ }
+
+ inputs := rule.Implicits.Strings()
sort.Strings(inputs)
sort.Strings(expectedInputs)
+ outputs := append(android.WritablePaths{rule.Output}, rule.ImplicitOutputs...).Strings()
+ sort.Strings(outputs)
+ sort.Strings(expectedOutputs)
+
if !reflect.DeepEqual(inputs, expectedInputs) {
t.Errorf("want inputs %q\n got inputs %q", expectedInputs, inputs)
}
+ if !reflect.DeepEqual(outputs, expectedOutputs) {
+ t.Errorf("want outputs %q\n got outputs %q", expectedOutputs, outputs)
+ }
+}
+
+func TestDexpreoptBootJars(t *testing.T) {
+ ruleFile := "boot-foo.art"
+
+ expectedInputs := []string{
+ "dex_artjars/android/apex/com.android.art/javalib/arm64/boot.art",
+ "dex_bootjars_input/foo.jar",
+ "dex_bootjars_input/bar.jar",
+ "dex_bootjars_input/baz.jar",
+ }
+
expectedOutputs := []string{
"dex_bootjars/android/system/framework/arm64/boot.invocation",
-
"dex_bootjars/android/system/framework/arm64/boot-foo.art",
"dex_bootjars/android/system/framework/arm64/boot-bar.art",
"dex_bootjars/android/system/framework/arm64/boot-baz.art",
-
"dex_bootjars/android/system/framework/arm64/boot-foo.oat",
"dex_bootjars/android/system/framework/arm64/boot-bar.oat",
"dex_bootjars/android/system/framework/arm64/boot-baz.oat",
-
"dex_bootjars/android/system/framework/arm64/boot-foo.vdex",
"dex_bootjars/android/system/framework/arm64/boot-bar.vdex",
"dex_bootjars/android/system/framework/arm64/boot-baz.vdex",
-
"dex_bootjars_unstripped/android/system/framework/arm64/boot-foo.oat",
"dex_bootjars_unstripped/android/system/framework/arm64/boot-bar.oat",
"dex_bootjars_unstripped/android/system/framework/arm64/boot-baz.oat",
}
- for i := range expectedOutputs {
- expectedOutputs[i] = filepath.Join(buildDir, "test_device", expectedOutputs[i])
- }
+ testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs)
+}
- outputs := append(android.WritablePaths{bootArt.Output}, bootArt.ImplicitOutputs...).Strings()
- sort.Strings(outputs)
- sort.Strings(expectedOutputs)
+// Changes to the boot.zip structure may break the ART APK scanner.
+func TestDexpreoptBootZip(t *testing.T) {
+ ruleFile := "boot.zip"
+
+ ctx := android.PathContextForTesting(testConfig(nil, "", nil))
+ expectedInputs := []string{}
+ for _, target := range dexpreoptTargets(ctx) {
+ for _, ext := range []string{".art", ".oat", ".vdex"} {
+ for _, jar := range []string{"foo", "bar", "baz"} {
+ expectedInputs = append(expectedInputs,
+ filepath.Join("dex_bootjars", target.Os.String(), "system/framework", target.Arch.ArchType.String(), "boot-"+jar+ext))
+ }
+ }
+ }
- if !reflect.DeepEqual(outputs, expectedOutputs) {
- t.Errorf("want outputs %q\n got outputs %q", expectedOutputs, outputs)
+ expectedOutputs := []string{
+ "dex_bootjars/boot.zip",
}
+
+ testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs)
}
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 41a2ca794..f13d9f210 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -39,7 +39,7 @@ func systemServerClasspath(ctx android.MakeVarsContext) []string {
// 2) The jars that are from an updatable apex.
for _, m := range global.UpdatableSystemServerJars {
systemServerClasspathLocations = append(systemServerClasspathLocations,
- dexpreopt.GetJarLocationFromApexJarPair(m))
+ dexpreopt.GetJarLocationFromApexJarPair(ctx, m))
}
if len(systemServerClasspathLocations) != len(global.SystemServerJars)+len(global.UpdatableSystemServerJars) {
panic(fmt.Errorf("Wrong number of system server jars, got %d, expected %d",
@@ -80,7 +80,7 @@ func stemOf(moduleName string) string {
}
func getDexLocation(ctx android.PathContext, target android.Target, module string) string {
- apex, jar := android.SplitApexJarPair(module)
+ apex, jar := android.SplitApexJarPair(ctx, module)
name := stemOf(jar) + ".jar"
@@ -156,7 +156,7 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
c.symbolsDir = deviceDir.Join(ctx, "dex_"+c.name+"jars_unstripped")
// expands to <stem>.art for primary image and <stem>-<1st module>.art for extension
- imageName := c.firstModuleNameOrStem() + ".art"
+ imageName := c.firstModuleNameOrStem(ctx) + ".art"
// The path to bootclasspath dex files needs to be known at module
// GenerateAndroidBuildAction time, before the bootclasspath modules have been compiled.
@@ -164,7 +164,7 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
// TODO(b/143682396): use module dependencies instead
inputDir := deviceDir.Join(ctx, "dex_"+c.name+"jars_input")
for _, m := range c.modules {
- _, jar := android.SplitApexJarPair(m)
+ _, jar := android.SplitApexJarPair(ctx, m)
c.dexPaths = append(c.dexPaths, inputDir.Join(ctx, stemOf(jar)+".jar"))
}
c.dexPathsDeps = c.dexPaths
@@ -215,7 +215,7 @@ func defaultBootclasspath(ctx android.PathContext) []string {
updatableBootclasspath := make([]string, len(global.UpdatableBootJars))
for i, p := range global.UpdatableBootJars {
- updatableBootclasspath[i] = dexpreopt.GetJarLocationFromApexJarPair(p)
+ updatableBootclasspath[i] = dexpreopt.GetJarLocationFromApexJarPair(ctx, p)
}
bootclasspath := append(copyOf(image.getAnyAndroidVariant().dexLocationsDeps), updatableBootclasspath...)
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 78ecb09e3..b16c9cd72 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -222,8 +222,22 @@ type DroidstubsProperties struct {
Current ApiToCheck
- // do not perform API check against Last_released, in the case that both two specified API
- // files by Last_released are modules which don't exist.
+ // The java_sdk_library module generates references to modules (i.e. filegroups)
+ // from which information about the latest API version can be obtained. As those
+ // modules may not exist (e.g. because a previous version has not been released) it
+ // sets ignore_missing_latest_api=true on the droidstubs modules it creates so
+ // that droidstubs can ignore those references if the modules do not yet exist.
+ //
+ // If true then this will ignore module references for modules that do not exist
+ // in properties that supply the previous version of the API.
+ //
+ // There are two sets of those:
+ // * Api_file, Removed_api_file in check_api.last_released
+ // * New_since in check_api.api_lint.new_since
+ //
+ // The first two must be set as a pair, so either they should both exist or neither
+ // should exist - in which case when this property is true they are ignored. If one
+ // exists and the other does not then it is an error.
Ignore_missing_latest_api *bool `blueprint:"mutated"`
Api_lint struct {
@@ -337,11 +351,16 @@ type ApiFilePath interface {
ApiFilePath() android.Path
}
+type ApiStubsSrcProvider interface {
+ StubsSrcJar() android.Path
+}
+
// Provider of information about API stubs, used by java_sdk_library.
type ApiStubsProvider interface {
ApiFilePath
RemovedApiFilePath() android.Path
- StubsSrcJar() android.Path
+
+ ApiStubsSrcProvider
}
//
@@ -357,6 +376,7 @@ type Javadoc struct {
srcFiles android.Paths
sourcepaths android.Paths
argFiles android.Paths
+ implicits android.Paths
args string
@@ -527,7 +547,7 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps {
case libTag:
switch dep := module.(type) {
case SdkLibraryDependency:
- deps.classpath = append(deps.classpath, dep.SdkImplementationJars(ctx, j.sdkVersion())...)
+ deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
case Dependency:
deps.classpath = append(deps.classpath, dep.HeaderJars()...)
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
@@ -556,6 +576,7 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps {
// do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs
// may contain filegroup or genrule.
srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
+ j.implicits = append(j.implicits, srcFiles...)
filterByPackage := func(srcs []android.Path, filterPackages []string) []android.Path {
if filterPackages == nil {
@@ -581,6 +602,24 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps {
}
srcFiles = filterByPackage(srcFiles, j.properties.Filter_packages)
+ // While metalava needs package html files, it does not need them to be explicit on the command
+ // line. More importantly, the metalava rsp file is also used by the subsequent jdiff action if
+ // jdiff_enabled=true. javadoc complains if it receives html files on the command line. The filter
+ // below excludes html files from the rsp file for both metalava and jdiff. Note that the html
+ // files are still included as implicit inputs for successful remote execution and correct
+ // incremental builds.
+ filterHtml := func(srcs []android.Path) []android.Path {
+ filtered := []android.Path{}
+ for _, src := range srcs {
+ if src.Ext() == ".html" {
+ continue
+ }
+ filtered = append(filtered, src)
+ }
+ return filtered
+ }
+ srcFiles = filterHtml(srcFiles)
+
flags := j.collectAidlFlags(ctx, deps)
srcFiles = j.genSources(ctx, srcFiles, flags)
@@ -1200,8 +1239,18 @@ func (d *Droidstubs) StubsSrcJar() android.Path {
func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
d.Javadoc.addDeps(ctx)
+ // If requested clear any properties that provide information about the latest version
+ // of an API and which reference non-existent modules.
if Bool(d.properties.Check_api.Ignore_missing_latest_api) {
ignoreMissingModules(ctx, &d.properties.Check_api.Last_released)
+
+ // If the new_since references a module, e.g. :module-latest-api and the module
+ // does not exist then clear it.
+ newSinceSrc := d.properties.Check_api.Api_lint.New_since
+ newSinceSrcModule := android.SrcIsModule(proptools.String(newSinceSrc))
+ if newSinceSrcModule != "" && !ctx.OtherModuleExists(newSinceSrcModule) {
+ d.properties.Check_api.Api_lint.New_since = nil
+ }
}
if len(d.properties.Merge_annotations_dirs) != 0 {
@@ -1373,10 +1422,26 @@ func (d *Droidstubs) apiToXmlFlags(ctx android.ModuleContext, cmd *android.RuleB
}
func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
- srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths) *android.RuleBuilderCommand {
+ srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths, implicits android.Paths) *android.RuleBuilderCommand {
// Metalava uses lots of memory, restrict the number of metalava jobs that can run in parallel.
rule.HighMem()
cmd := rule.Command()
+
+ rspFile := ""
+ if len(implicits) > 0 {
+ implicitsRsp := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"implicits.rsp")
+ rspFile = implicitsRsp.String()
+ impRule := android.NewRuleBuilder()
+ impCmd := impRule.Command()
+ // A dummy action that copies the ninja generated rsp file to a new location. This allows us to
+ // add a large number of inputs to a file without exceeding bash command length limits (which
+ // would happen if we use the WriteFile rule). The cp is needed because RuleBuilder sets the
+ // rsp file to be ${output}.rsp.
+ impCmd.Text("cp").FlagWithRspFileInputList("", implicits).Output(implicitsRsp)
+ impRule.Build(pctx, ctx, "implicitsGen", "implicits generation")
+ cmd.Implicits(implicits)
+ cmd.Implicit(implicitsRsp)
+ }
if ctx.Config().IsEnvTrue("RBE_METALAVA") {
rule.Remoteable(android.RemoteRuleSupports{RBE: true})
execStrategy := remoteexec.LocalExecStrategy
@@ -1388,7 +1453,6 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi
pool = v
}
inputs := []string{android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "metalava.jar").String()}
- inputs = append(inputs, sourcepaths.Strings()...)
if v := ctx.Config().Getenv("RBE_METALAVA_INPUTS"); v != "" {
inputs = append(inputs, strings.Split(v, ",")...)
}
@@ -1396,6 +1460,7 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi
Labels: map[string]string{"type": "compile", "lang": "java", "compiler": "metalava"},
ExecStrategy: execStrategy,
Inputs: inputs,
+ RSPFile: rspFile,
ToolchainInputs: []string{config.JavaCmd(ctx).String()},
Platform: map[string]string{remoteexec.PoolKey: pool},
}).NoVarTemplate(ctx.Config()))
@@ -1453,7 +1518,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
- deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths)
+ deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths, d.Javadoc.implicits)
d.stubsFlags(ctx, cmd, stubsDir)
@@ -1908,6 +1973,10 @@ func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
}
}
+func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
+ return d.stubsSrcJar
+}
+
func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
p.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index 884a757e2..ce624bfc1 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -180,7 +180,9 @@ func hiddenAPIEncodeDex(ctx android.ModuleContext, output android.WritablePath,
// b/149353192: when a module is instrumented, jacoco adds synthetic members
// $jacocoData and $jacocoInit. Since they don't exist when building the hidden API flags,
// don't complain when we don't find hidden API flags for the synthetic members.
- if j, ok := ctx.Module().(*Library); ok && j.shouldInstrument(ctx) {
+ if j, ok := ctx.Module().(interface {
+ shouldInstrument(android.BaseModuleContext) bool
+ }); ok && j.shouldInstrument(ctx) {
enforceHiddenApiFlagsToAllMembers = false
}
diff --git a/java/java.go b/java/java.go
index 9d75c74c7..76bfa86d6 100644
--- a/java/java.go
+++ b/java/java.go
@@ -95,8 +95,7 @@ func (j *Module) CheckStableSdkVersion() error {
}
func (j *Module) checkSdkVersions(ctx android.ModuleContext) {
- if j.SocSpecific() || j.DeviceSpecific() ||
- (j.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
+ if j.RequiresStableAPIs(ctx) {
if sc, ok := ctx.Module().(sdkContext); ok {
if !sc.sdkVersion().specified() {
ctx.PropertyErrorf("sdk_version",
@@ -343,14 +342,45 @@ type CompilerDeviceProperties struct {
// set the name of the output
Stem *string
- UncompressDex bool `blueprint:"mutated"`
- IsSDKLibrary bool `blueprint:"mutated"`
+ // Keep the data uncompressed. We always need uncompressed dex for execution,
+ // so this might actually save space by avoiding storing the same data twice.
+ // This defaults to reasonable value based on module and should not be set.
+ // It exists only to support ART tests.
+ Uncompress_dex *bool
+
+ IsSDKLibrary bool `blueprint:"mutated"`
}
func (me *CompilerDeviceProperties) EffectiveOptimizeEnabled() bool {
return BoolDefault(me.Optimize.Enabled, me.Optimize.EnabledByDefault)
}
+// Functionality common to Module and Import
+//
+// It is embedded in Module so its functionality can be used by methods in Module
+// but it is currently only initialized by Import and Library.
+type embeddableInModuleAndImport struct {
+
+ // Functionality related to this being used as a component of a java_sdk_library.
+ EmbeddableSdkLibraryComponent
+}
+
+func (e *embeddableInModuleAndImport) initModuleAndImport(moduleBase *android.ModuleBase) {
+ e.initSdkLibraryComponent(moduleBase)
+}
+
+// Module/Import's DepIsInSameApex(...) delegates to this method.
+//
+// This cannot implement DepIsInSameApex(...) directly as that leads to ambiguity with
+// the one provided by ApexModuleBase.
+func (e *embeddableInModuleAndImport) depIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+ // dependencies other than the static linkage are all considered crossing APEX boundary
+ if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
+ return true
+ }
+ return false
+}
+
// Module contains the properties and members used by all java module types
type Module struct {
android.ModuleBase
@@ -358,6 +388,9 @@ type Module struct {
android.ApexModuleBase
android.SdkBase
+ // Functionality common to Module and Import.
+ embeddableInModuleAndImport
+
properties CompilerProperties
protoProperties android.ProtoProperties
deviceProperties CompilerDeviceProperties
@@ -443,6 +476,9 @@ type Module struct {
kytheFiles android.Paths
distFile android.Path
+
+ // Collect the module directory for IDE info in java/jdeps.go.
+ modulePaths []string
}
func (j *Module) OutputFiles(tag string) (android.Paths, error) {
@@ -474,11 +510,6 @@ type Dependency interface {
JacocoReportClassesFile() android.Path
}
-type SdkLibraryDependency interface {
- SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths
- SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths
-}
-
type xref interface {
XrefJavaFiles() android.Paths
}
@@ -625,13 +656,15 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) {
}
} else if sdkDep.useModule {
ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
- ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
if j.deviceProperties.EffectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultBootclasspathLibraries...)
ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultLibraries...)
}
}
+ if sdkDep.systemModules != "" {
+ ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
+ }
if ctx.ModuleName() == "android_stubs_current" ||
ctx.ModuleName() == "android_system_stubs_current" ||
@@ -906,6 +939,12 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
}
}
+ // If this is a component library (stubs, etc.) for a java_sdk_library then
+ // add the name of that java_sdk_library to the exported sdk libs to make sure
+ // that, if necessary, a <uses-library> element for that java_sdk_library is
+ // added to the Android manifest.
+ j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...)
+
ctx.VisitDirectDeps(func(module android.Module) {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
@@ -925,7 +964,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
case libTag:
deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
// names of sdk libs that are directly depended are exported
- j.exportedSdkLibs = append(j.exportedSdkLibs, otherName)
+ j.exportedSdkLibs = append(j.exportedSdkLibs, dep.OptionalImplicitSdkLibrary()...)
case staticLibTag:
ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
}
@@ -1034,19 +1073,10 @@ func addPlugins(deps *deps, pluginJars android.Paths, pluginClasses ...string) {
}
func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext sdkContext) javaVersion {
- sdk, err := sdkContext.sdkVersion().effectiveVersion(ctx)
- if err != nil {
- ctx.PropertyErrorf("sdk_version", "%s", err)
- }
if javaVersion != "" {
return normalizeJavaVersion(ctx, javaVersion)
- } else if ctx.Device() && sdk <= 23 {
- return JAVA_VERSION_7
- } else if ctx.Device() && sdk <= 29 {
- return JAVA_VERSION_8
- } else if ctx.Device() && ctx.Config().UnbundledBuildUsePrebuiltSdks() {
- // TODO(b/142896162): once we have prebuilt system modules we can use 1.9 for unbundled builds
- return JAVA_VERSION_8
+ } else if ctx.Device() {
+ return sdkContext.sdkVersion().defaultJavaLanguageVersion(ctx)
} else {
return JAVA_VERSION_9
}
@@ -1426,13 +1456,19 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
serviceFile := file.String()
zipargs = append(zipargs, "-C", filepath.Dir(serviceFile), "-f", serviceFile)
}
+ rule := zip
+ args := map[string]string{
+ "jarArgs": "-P META-INF/services/ " + strings.Join(proptools.NinjaAndShellEscapeList(zipargs), " "),
+ }
+ if ctx.Config().IsEnvTrue("RBE_ZIP") {
+ rule = zipRE
+ args["implicits"] = strings.Join(services.Strings(), ",")
+ }
ctx.Build(pctx, android.BuildParams{
- Rule: zip,
+ Rule: rule,
Output: servicesJar,
Implicits: services,
- Args: map[string]string{
- "jarArgs": "-P META-INF/services/ " + strings.Join(proptools.NinjaAndShellEscapeList(zipargs), " "),
- },
+ Args: args,
})
jars = append(jars, servicesJar)
}
@@ -1545,7 +1581,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
// Hidden API CSV generation and dex encoding
dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, dexOutputFile, j.implementationJarFile,
- j.deviceProperties.UncompressDex)
+ proptools.Bool(j.deviceProperties.Uncompress_dex))
// merge dex jar with resources if necessary
if j.resourceJar != nil {
@@ -1553,7 +1589,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
combinedJar := android.PathForModuleOut(ctx, "dex-withres", jarName)
TransformJarsToJar(ctx, combinedJar, "for dex resources", jars, android.OptionalPath{},
false, nil, nil)
- if j.deviceProperties.UncompressDex {
+ if *j.deviceProperties.Uncompress_dex {
combinedAlignedJar := android.PathForModuleOut(ctx, "dex-withres-aligned", jarName)
TransformZipAlign(ctx, combinedAlignedJar, combinedJar)
dexOutputFile = combinedAlignedJar
@@ -1754,6 +1790,7 @@ func (j *Module) IDEInfo(dpInfo *android.IdeInfo) {
if j.expandJarjarRules != nil {
dpInfo.Jarjar_rules = append(dpInfo.Jarjar_rules, j.expandJarjarRules.String())
}
+ dpInfo.Paths = append(dpInfo.Paths, j.modulePaths...)
}
func (j *Module) CompilerDeps() []string {
@@ -1769,11 +1806,7 @@ func (j *Module) hasCode(ctx android.ModuleContext) bool {
}
func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
- // Dependencies other than the static linkage are all considered crossing APEX boundary
- if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
- return true
- }
- return false
+ return j.depIsInSameApex(ctx, dep)
}
func (j *Module) Stem() string {
@@ -1807,6 +1840,17 @@ type Library struct {
InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths)
}
+// Provides access to the list of permitted packages from updatable boot jars.
+type PermittedPackagesForUpdatableBootJars interface {
+ PermittedPackagesForUpdatableBootJars() []string
+}
+
+var _ PermittedPackagesForUpdatableBootJars = (*Library)(nil)
+
+func (j *Library) PermittedPackagesForUpdatableBootJars() []string {
+ return j.properties.Permitted_packages
+}
+
func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bool {
// Store uncompressed (and aligned) any dex files from jars in APEXes.
if am, ok := ctx.Module().(android.ApexModule); ok && !am.IsForPlatform() {
@@ -1834,10 +1878,16 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.checkSdkVersions(ctx)
j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
- j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
- j.deviceProperties.UncompressDex = j.dexpreopter.uncompressedDex
+ if j.deviceProperties.Uncompress_dex == nil {
+ // If the value was not force-set by the user, use reasonable default based on the module.
+ j.deviceProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter))
+ }
+ j.dexpreopter.uncompressedDex = *j.deviceProperties.Uncompress_dex
j.compile(ctx, nil)
+ // Collect the module directory for IDE info in java/jdeps.go.
+ j.modulePaths = append(j.modulePaths, ctx.ModuleDir())
+
exclusivelyForApex := android.InAnyApex(ctx.ModuleName()) && !j.IsForPlatform()
if (Bool(j.properties.Installable) || ctx.Host()) && !exclusivelyForApex {
var extraInstallDeps android.Paths
@@ -1845,7 +1895,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
extraInstallDeps = j.InstallMixin(ctx, j.outputFile)
}
j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
- ctx.ModuleName()+".jar", j.outputFile, extraInstallDeps...)
+ j.Stem()+".jar", j.outputFile, extraInstallDeps...)
}
// Verify Dist.Tag is set to a supported output
@@ -1979,6 +2029,8 @@ func LibraryFactory() android.Module {
&module.Module.protoProperties,
&module.libraryProperties)
+ module.initModuleAndImport(&module.ModuleBase)
+
android.InitApexModule(module)
android.InitSdkAwareModule(module)
InitJavaModule(module, android.HostAndDeviceSupported)
@@ -2033,6 +2085,10 @@ type testProperties struct {
// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
// explicitly.
Auto_gen_config *bool
+
+ // Add parameterized mainline modules to auto generated test config. The options will be
+ // handled by TradeFed to do downloading and installing the specified modules on the device.
+ Test_mainline_modules []string
}
type testHelperLibraryProperties struct {
@@ -2387,6 +2443,9 @@ type Import struct {
prebuilt android.Prebuilt
android.SdkBase
+ // Functionality common to Module and Import.
+ embeddableInModuleAndImport
+
properties ImportProperties
combinedClasspathFile android.Path
@@ -2444,6 +2503,12 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
j.combinedClasspathFile = outputFile
+ // If this is a component library (impl, stubs, etc.) for a java_sdk_library then
+ // add the name of that java_sdk_library to the exported sdk libs to make sure
+ // that, if necessary, a <uses-library> element for that java_sdk_library is
+ // added to the Android manifest.
+ j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...)
+
ctx.VisitDirectDeps(func(module android.Module) {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
@@ -2521,11 +2586,7 @@ func (j *Import) SrcJarArgs() ([]string, android.Paths) {
}
func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
- // dependencies other than the static linkage are all considered crossing APEX boundary
- if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
- return true
- }
- return false
+ return j.depIsInSameApex(ctx, dep)
}
// Add compile time check for interface implementation
@@ -2566,6 +2627,8 @@ func ImportFactory() android.Module {
module.AddProperties(&module.properties)
+ module.initModuleAndImport(&module.ModuleBase)
+
android.InitPrebuiltModule(module, &module.properties.Jars)
android.InitApexModule(module)
android.InitSdkAwareModule(module)
@@ -2682,7 +2745,7 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.maybeStrippedDexJarFile = dexOutputFile
ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
- ctx.ModuleName()+".jar", dexOutputFile)
+ j.Stem()+".jar", dexOutputFile)
}
func (j *DexImport) DexJar() android.Path {
@@ -2764,6 +2827,7 @@ func DefaultsFactory() android.Module {
&ImportProperties{},
&AARImportProperties{},
&sdkLibraryProperties{},
+ &commonToSdkLibraryAndImportProperties{},
&DexImportProperties{},
&android.ApexProperties{},
&RuntimeResourceOverlayProperties{},
diff --git a/java/java_test.go b/java/java_test.go
index 0033f319d..8ea34d975 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -19,6 +19,8 @@ import (
"os"
"path/filepath"
"reflect"
+ "regexp"
+ "sort"
"strconv"
"strings"
"testing"
@@ -575,6 +577,7 @@ func TestJavaSdkLibraryImport(t *testing.T) {
},
test: {
jars: ["c.jar"],
+ stub_srcs: ["c.java"],
},
}
`)
@@ -1035,7 +1038,7 @@ func checkSystemModulesUseByDroidstubs(t *testing.T, ctx *android.TestContext, m
for _, i := range metalavaRule.Implicits {
systemJars = append(systemJars, i.Base())
}
- if len(systemJars) != 1 || systemJars[0] != systemJar {
+ if len(systemJars) < 1 || systemJars[0] != systemJar {
t.Errorf("inputs of %q must be []string{%q}, but was %#v.", moduleName, systemJar, systemJars)
}
}
@@ -1152,13 +1155,42 @@ func TestJavaSdkLibrary(t *testing.T) {
java_library {
name: "baz",
srcs: ["c.java"],
- libs: ["foo", "bar"],
+ libs: ["foo", "bar.stubs"],
sdk_version: "system_current",
}
+ java_sdk_library {
+ name: "barney",
+ srcs: ["c.java"],
+ api_only: true,
+ }
+ java_sdk_library {
+ name: "betty",
+ srcs: ["c.java"],
+ shared_library: false,
+ }
+ java_sdk_library_import {
+ name: "quuz",
+ public: {
+ jars: ["c.jar"],
+ },
+ }
+ java_sdk_library_import {
+ name: "fred",
+ public: {
+ jars: ["b.jar"],
+ },
+ }
+ java_sdk_library_import {
+ name: "wilma",
+ public: {
+ jars: ["b.jar"],
+ },
+ shared_library: false,
+ }
java_library {
name: "qux",
srcs: ["c.java"],
- libs: ["baz"],
+ libs: ["baz", "fred", "quuz.stubs", "wilma", "barney", "betty"],
sdk_version: "system_current",
}
java_library {
@@ -1177,12 +1209,12 @@ func TestJavaSdkLibrary(t *testing.T) {
// check the existence of the internal modules
ctx.ModuleForTests("foo", "android_common")
- ctx.ModuleForTests("foo"+sdkStubsLibrarySuffix, "android_common")
- ctx.ModuleForTests("foo"+sdkStubsLibrarySuffix+sdkSystemApiSuffix, "android_common")
- ctx.ModuleForTests("foo"+sdkStubsLibrarySuffix+sdkTestApiSuffix, "android_common")
- ctx.ModuleForTests("foo"+sdkStubsSourceSuffix, "android_common")
- ctx.ModuleForTests("foo"+sdkStubsSourceSuffix+sdkSystemApiSuffix, "android_common")
- ctx.ModuleForTests("foo"+sdkStubsSourceSuffix+sdkTestApiSuffix, "android_common")
+ ctx.ModuleForTests(apiScopePublic.stubsLibraryModuleName("foo"), "android_common")
+ ctx.ModuleForTests(apiScopeSystem.stubsLibraryModuleName("foo"), "android_common")
+ ctx.ModuleForTests(apiScopeTest.stubsLibraryModuleName("foo"), "android_common")
+ ctx.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo"), "android_common")
+ ctx.ModuleForTests(apiScopeSystem.stubsSourceModuleName("foo"), "android_common")
+ ctx.ModuleForTests(apiScopeTest.stubsSourceModuleName("foo"), "android_common")
ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
ctx.ModuleForTests("foo.api.public.28", "")
ctx.ModuleForTests("foo.api.system.28", "")
@@ -1223,12 +1255,145 @@ func TestJavaSdkLibrary(t *testing.T) {
qux := ctx.ModuleForTests("qux", "android_common")
if quxLib, ok := qux.Module().(*Library); ok {
sdkLibs := quxLib.ExportedSdkLibs()
- if len(sdkLibs) != 2 || !android.InList("foo", sdkLibs) || !android.InList("bar", sdkLibs) {
- t.Errorf("qux should export \"foo\" and \"bar\" but exports %v", sdkLibs)
+ sort.Strings(sdkLibs)
+ if w := []string{"bar", "foo", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) {
+ t.Errorf("qux should export %q but exports %q", w, sdkLibs)
+ }
+ }
+}
+
+func TestJavaSdkLibrary_DoNotAccessImplWhenItIsNotBuilt(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ api_only: true,
+ public: {
+ enabled: true,
+ },
}
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ libs: ["foo"],
+ }
+ `)
+
+ // The bar library should depend on the stubs jar.
+ barLibrary := ctx.ModuleForTests("bar", "android_common").Rule("javac")
+ if expected, actual := `^-classpath .*:/[^:]*/turbine-combined/foo\.stubs\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
+ t.Errorf("expected %q, found %#q", expected, actual)
}
}
+func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) {
+ testJava(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ api_packages: ["foo"],
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java", ":foo{.public.stubs.source}"],
+ }
+ `)
+}
+
+func TestJavaSdkLibrary_AccessOutputFiles_MissingScope(t *testing.T) {
+ testJavaError(t, `"foo" does not provide api scope system`, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ api_packages: ["foo"],
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java", ":foo{.system.stubs.source}"],
+ }
+ `)
+}
+
+func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) {
+ testJava(t, `
+ java_sdk_library_import {
+ name: "foo",
+ public: {
+ jars: ["a.jar"],
+ stub_srcs: ["a.java"],
+ current_api: "api/current.txt",
+ removed_api: "api/removed.txt",
+ },
+ }
+
+ java_library {
+ name: "bar",
+ srcs: [":foo{.public.stubs.source}"],
+ java_resources: [
+ ":foo{.public.api.txt}",
+ ":foo{.public.removed-api.txt}",
+ ],
+ }
+ `)
+}
+
+func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) {
+ bp := `
+ java_sdk_library_import {
+ name: "foo",
+ public: {
+ jars: ["a.jar"],
+ },
+ }
+ `
+
+ t.Run("stubs.source", func(t *testing.T) {
+ testJavaError(t, `stubs.source not available for api scope public`, bp+`
+ java_library {
+ name: "bar",
+ srcs: [":foo{.public.stubs.source}"],
+ java_resources: [
+ ":foo{.public.api.txt}",
+ ":foo{.public.removed-api.txt}",
+ ],
+ }
+ `)
+ })
+
+ t.Run("api.txt", func(t *testing.T) {
+ testJavaError(t, `api.txt not available for api scope public`, bp+`
+ java_library {
+ name: "bar",
+ srcs: ["a.java"],
+ java_resources: [
+ ":foo{.public.api.txt}",
+ ],
+ }
+ `)
+ })
+
+ t.Run("removed-api.txt", func(t *testing.T) {
+ testJavaError(t, `removed-api.txt not available for api scope public`, bp+`
+ java_library {
+ name: "bar",
+ srcs: ["a.java"],
+ java_resources: [
+ ":foo{.public.removed-api.txt}",
+ ],
+ }
+ `)
+ })
+}
+
func TestJavaSdkLibrary_InvalidScopes(t *testing.T) {
testJavaError(t, `module "foo": enabled api scope "system" depends on disabled scope "public"`, `
java_sdk_library {
@@ -1247,6 +1412,86 @@ func TestJavaSdkLibrary_InvalidScopes(t *testing.T) {
`)
}
+func TestJavaSdkLibrary_SdkVersion_ForScope(t *testing.T) {
+ testJava(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ system: {
+ enabled: true,
+ sdk_version: "module_current",
+ },
+ }
+ `)
+}
+
+func TestJavaSdkLibrary_MissingScope(t *testing.T) {
+ testJavaError(t, `requires api scope module-lib from foo but it only has \[\] available`, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ public: {
+ enabled: false,
+ },
+ }
+
+ java_library {
+ name: "baz",
+ srcs: ["a.java"],
+ libs: ["foo"],
+ sdk_version: "module_current",
+ }
+ `)
+}
+
+func TestJavaSdkLibrary_FallbackScope(t *testing.T) {
+ testJava(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ system: {
+ enabled: true,
+ },
+ }
+
+ java_library {
+ name: "baz",
+ srcs: ["a.java"],
+ libs: ["foo"],
+ // foo does not have module-lib scope so it should fallback to system
+ sdk_version: "module_current",
+ }
+ `)
+}
+
+func TestJavaSdkLibrary_DefaultToStubs(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ system: {
+ enabled: true,
+ },
+ default_to_stubs: true,
+ }
+
+ java_library {
+ name: "baz",
+ srcs: ["a.java"],
+ libs: ["foo"],
+ // does not have sdk_version set, should fallback to module,
+ // which will then fallback to system because the module scope
+ // is not enabled.
+ }
+ `)
+ // The baz library should depend on the system stubs jar.
+ bazLibrary := ctx.ModuleForTests("baz", "android_common").Rule("javac")
+ if expected, actual := `^-classpath .*:/[^:]*/turbine-combined/foo\.stubs.system\.jar$`, bazLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
+ t.Errorf("expected %q, found %#q", expected, actual)
+ }
+}
+
var compilerFlagsTestCases = []struct {
in string
out bool
diff --git a/java/jdeps.go b/java/jdeps.go
index 49e3de3cc..9f4388733 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -72,6 +72,7 @@ func (j *jdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonCont
dpInfo.Jarjar_rules = android.FirstUniqueStrings(dpInfo.Jarjar_rules)
dpInfo.Jars = android.FirstUniqueStrings(dpInfo.Jars)
dpInfo.SrcJars = android.FirstUniqueStrings(dpInfo.SrcJars)
+ dpInfo.Paths = android.FirstUniqueStrings(dpInfo.Paths)
moduleInfos[name] = dpInfo
mkProvider, ok := module.(android.AndroidMkDataProvider)
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 03bc76bf2..999c72f3c 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -15,11 +15,12 @@
package java
import (
- "android/soong/android"
"sort"
"strings"
"github.com/google/blueprint/proptools"
+
+ "android/soong/android"
)
func init() {
@@ -69,6 +70,10 @@ func parseApiFilePath(ctx android.LoadHookContext, path string) (module string,
return
}
+func prebuiltApiModuleName(mctx android.LoadHookContext, module string, scope string, apiver string) string {
+ return mctx.ModuleName() + "_" + scope + "_" + apiver + "_" + module
+}
+
func createImport(mctx android.LoadHookContext, module string, scope string, apiver string, path string) {
props := struct {
Name *string
@@ -76,7 +81,7 @@ func createImport(mctx android.LoadHookContext, module string, scope string, api
Sdk_version *string
Installable *bool
}{}
- props.Name = proptools.StringPtr(mctx.ModuleName() + "_" + scope + "_" + apiver + "_" + module)
+ props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, apiver))
props.Jars = append(props.Jars, path)
// TODO(hansson): change to scope after migration is done.
props.Sdk_version = proptools.StringPtr("current")
@@ -124,6 +129,27 @@ func prebuiltSdkStubs(mctx android.LoadHookContext) {
}
}
+func createSystemModules(mctx android.LoadHookContext, apiver 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))
+
+ mctx.CreateModule(SystemModulesFactory, &props)
+}
+
+func prebuiltSdkSystemModules(mctx android.LoadHookContext) {
+ for _, apiver := range mctx.Module().(*prebuiltApis).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) {
mydir := mctx.ModuleDir() + "/"
// <apiver>/<scope>/api/<module>.txt
@@ -178,6 +204,7 @@ func createPrebuiltApiModules(mctx android.LoadHookContext) {
if _, ok := mctx.Module().(*prebuiltApis); ok {
prebuiltApiFiles(mctx)
prebuiltSdkStubs(mctx)
+ prebuiltSdkSystemModules(mctx)
}
}
@@ -191,7 +218,9 @@ func createPrebuiltApiModules(mctx android.LoadHookContext) {
// Similarly, it generates a java_import for all API .jar files found under the
// directory where the Android.bp is located. Specifically, an API file located
// at ./<ver>/<scope>/api/<module>.jar generates a java_import module named
-// <prebuilt-api-module>.<scope>.<ver>.<module>.
+// <prebuilt-api-module>_<scope>_<ver>_<module>, and for SDK versions >= 30
+// a java_system_modules module named
+// <prebuilt-api-module>_public_<ver>_system_modules
func PrebuiltApisFactory() android.Module {
module := &prebuiltApis{}
module.AddProperties(&module.properties)
diff --git a/java/sdk.go b/java/sdk.go
index 690451c60..9310f7846 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -252,6 +252,20 @@ func (s sdkSpec) effectiveVersionString(ctx android.EarlyModuleContext) (string,
return ver.String(), err
}
+func (s sdkSpec) defaultJavaLanguageVersion(ctx android.EarlyModuleContext) javaVersion {
+ sdk, err := s.effectiveVersion(ctx)
+ if err != nil {
+ ctx.PropertyErrorf("sdk_version", "%s", err)
+ }
+ if sdk <= 23 {
+ return JAVA_VERSION_7
+ } else if sdk <= 29 {
+ return JAVA_VERSION_8
+ } else {
+ return JAVA_VERSION_9
+ }
+}
+
func sdkSpecFrom(str string) sdkSpec {
switch str {
// special cases first
@@ -370,10 +384,16 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep
return sdkDep{}
}
+ var systemModules string
+ if sdkVersion.defaultJavaLanguageVersion(ctx).usesJavaModules() {
+ systemModules = "sdk_public_" + sdkVersion.version.String() + "_system_modules"
+ }
+
return sdkDep{
- useFiles: true,
- jars: android.Paths{jarPath.Path(), lambdaStubsPath},
- aidl: android.OptionalPathForPath(aidlPath.Path()),
+ useFiles: true,
+ jars: android.Paths{jarPath.Path(), lambdaStubsPath},
+ aidl: android.OptionalPathForPath(aidlPath.Path()),
+ systemModules: systemModules,
}
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 2c85c8c09..c4d257f20 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -19,6 +19,7 @@ import (
"path"
"path/filepath"
"reflect"
+ "regexp"
"sort"
"strings"
"sync"
@@ -30,12 +31,8 @@ import (
)
const (
- sdkStubsLibrarySuffix = ".stubs"
- sdkSystemApiSuffix = ".system"
- sdkTestApiSuffix = ".test"
- sdkStubsSourceSuffix = ".stubs.source"
- sdkXmlFileSuffix = ".xml"
- permissionsTemplate = `<?xml version=\"1.0\" encoding=\"utf-8\"?>\n` +
+ 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` +
@@ -96,9 +93,18 @@ type apiScope struct {
// The name of the field in the dynamically created structure.
fieldName string
+ // The name of the property in the java_sdk_library_import
+ propertyName string
+
// The tag to use to depend on the stubs library module.
stubsTag scopeDependencyTag
+ // The tag to use to depend on the stubs source module (if separate from the API module).
+ stubsSourceTag scopeDependencyTag
+
+ // The tag to use to depend on the API file generating module (if separate from the stubs source module).
+ apiFileTag scopeDependencyTag
+
// The tag to use to depend on the stubs source and API module.
stubsSourceAndApiTag scopeDependencyTag
@@ -117,6 +123,22 @@ type apiScope struct {
// Extra arguments to pass to droidstubs for this scope.
droidstubsArgs []string
+ // The args that must be passed to droidstubs to generate the stubs source
+ // for this scope.
+ //
+ // The stubs source must include the definitions of everything that is in this
+ // api scope and all the scopes that this one extends.
+ droidstubsArgsForGeneratingStubsSource []string
+
+ // The args that must be passed to droidstubs to generate the API for this scope.
+ //
+ // The API only includes the additional members that this scope adds over the scope
+ // that it extends.
+ droidstubsArgsForGeneratingApi []string
+
+ // True if the stubs source and api can be created by the same metalava invocation.
+ createStubsSourceAndApiTogether bool
+
// Whether the api scope can be treated as unstable, and should skip compat checks.
unstable bool
}
@@ -124,26 +146,63 @@ type apiScope struct {
// Initialize a scope, creating and adding appropriate dependency tags
func initApiScope(scope *apiScope) *apiScope {
name := scope.name
- scope.fieldName = proptools.FieldNameForProperty(name)
+ scopeByName[name] = scope
+ allScopeNames = append(allScopeNames, name)
+ scope.propertyName = strings.ReplaceAll(name, "-", "_")
+ scope.fieldName = proptools.FieldNameForProperty(scope.propertyName)
scope.stubsTag = scopeDependencyTag{
name: name + "-stubs",
apiScope: scope,
depInfoExtractor: (*scopePaths).extractStubsLibraryInfoFromDependency,
}
+ scope.stubsSourceTag = scopeDependencyTag{
+ name: name + "-stubs-source",
+ apiScope: scope,
+ depInfoExtractor: (*scopePaths).extractStubsSourceInfoFromDep,
+ }
+ scope.apiFileTag = scopeDependencyTag{
+ name: name + "-api",
+ apiScope: scope,
+ depInfoExtractor: (*scopePaths).extractApiInfoFromDep,
+ }
scope.stubsSourceAndApiTag = scopeDependencyTag{
name: name + "-stubs-source-and-api",
apiScope: scope,
depInfoExtractor: (*scopePaths).extractStubsSourceAndApiInfoFromApiStubsProvider,
}
+
+ // To get the args needed to generate the stubs source append all the args from
+ // this scope and all the scopes it extends as each set of args adds additional
+ // members to the stubs.
+ var stubsSourceArgs []string
+ for s := scope; s != nil; s = s.extends {
+ stubsSourceArgs = append(stubsSourceArgs, s.droidstubsArgs...)
+ }
+ scope.droidstubsArgsForGeneratingStubsSource = stubsSourceArgs
+
+ // Currently the args needed to generate the API are the same as the args
+ // needed to add additional members.
+ apiArgs := scope.droidstubsArgs
+ scope.droidstubsArgsForGeneratingApi = apiArgs
+
+ // If the args needed to generate the stubs and API are the same then they
+ // can be generated in a single invocation of metalava, otherwise they will
+ // need separate invocations.
+ scope.createStubsSourceAndApiTogether = reflect.DeepEqual(stubsSourceArgs, apiArgs)
+
return scope
}
-func (scope *apiScope) stubsModuleName(baseName string) string {
- return baseName + sdkStubsLibrarySuffix + scope.moduleSuffix
+func (scope *apiScope) stubsLibraryModuleName(baseName string) string {
+ return baseName + ".stubs" + scope.moduleSuffix
}
func (scope *apiScope) stubsSourceModuleName(baseName string) string {
- return baseName + sdkStubsSourceSuffix + scope.moduleSuffix
+ return baseName + ".stubs.source" + scope.moduleSuffix
+}
+
+func (scope *apiScope) apiModuleName(baseName string) string {
+ return baseName + ".api" + scope.moduleSuffix
}
func (scope *apiScope) String() string {
@@ -161,6 +220,8 @@ func (scopes apiScopes) Strings(accessor func(*apiScope) string) []string {
}
var (
+ scopeByName = make(map[string]*apiScope)
+ allScopeNames []string
apiScopePublic = initApiScope(&apiScope{
name: "public",
@@ -183,7 +244,7 @@ var (
return &module.sdkLibraryProperties.System
},
apiFilePrefix: "system-",
- moduleSuffix: sdkSystemApiSuffix,
+ moduleSuffix: ".system",
sdkVersion: "system_current",
droidstubsArgs: []string{"-showAnnotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)"},
})
@@ -195,13 +256,13 @@ var (
return &module.sdkLibraryProperties.Test
},
apiFilePrefix: "test-",
- moduleSuffix: sdkTestApiSuffix,
+ moduleSuffix: ".test",
sdkVersion: "test_current",
droidstubsArgs: []string{"-showAnnotation android.annotation.TestApi"},
unstable: true,
})
apiScopeModuleLib = initApiScope(&apiScope{
- name: "module_lib",
+ name: "module-lib",
extends: apiScopeSystem,
// Module_lib scope is disabled by default in legacy mode.
//
@@ -268,9 +329,29 @@ type ApiScopeProperties struct {
// Otherwise, if this is not set for any scope then the default behavior is
// scope specific so please refer to the scope specific property documentation.
Enabled *bool
+
+ // 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.
+ //
+ // 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
+ // compiling the implementation library.
+ Sdk_version *string
}
type sdkLibraryProperties struct {
+ // Visibility for impl library module. If not specified then defaults to the
+ // visibility property.
+ Impl_library_visibility []string
+
// Visibility for stubs library modules. If not specified then defaults to the
// visibility property.
Stubs_library_visibility []string
@@ -295,7 +376,10 @@ type sdkLibraryProperties struct {
// Defaults to "api".
Api_dir *string
- // If set to true there is no runtime library.
+ // Determines whether a runtime implementation library is built; defaults to false.
+ //
+ // If true then it also prevents the module from being used as a shared module, i.e.
+ // it is as is shared_library: false, was set.
Api_only *bool
// local files that are used within user customized droiddoc options.
@@ -351,16 +435,48 @@ type sdkLibraryProperties struct {
// disabled by default.
Module_lib ApiScopeProperties
+ // Determines if the stubs are preferred over the implementation library
+ // for linking, even when the client doesn't specify sdk_version. When this
+ // is set to true, such clients are provided with the widest API surface that
+ // this lib provides. Note however that this option doesn't affect the clients
+ // that are in the same APEX as this library. In that case, the clients are
+ // always linked with the implementation library. Default is false.
+ Default_to_stubs *bool
+
+ // Properties related to api linting.
+ Api_lint struct {
+ // Enable api linting.
+ Enabled *bool
+ }
+
// TODO: determines whether to create HTML doc or not
//Html_doc *bool
}
+// Paths to outputs from java_sdk_library and java_sdk_library_import.
+//
+// Fields that are android.Paths are always set (during GenerateAndroidBuildActions).
+// OptionalPaths are always set by java_sdk_library but may not be set by
+// java_sdk_library_import as not all instances provide that information.
type scopePaths struct {
- stubsHeaderPath android.Paths
- stubsImplPath android.Paths
- currentApiFilePath android.Path
- removedApiFilePath android.Path
- stubsSrcJar android.Path
+ // The path (represented as Paths for convenience when returning) to the stubs header jar.
+ //
+ // That is the jar that is created by turbine.
+ stubsHeaderPath android.Paths
+
+ // The path (represented as Paths for convenience when returning) to the stubs implementation jar.
+ //
+ // This is not the implementation jar, it still only contains stubs.
+ stubsImplPath android.Paths
+
+ // The API specification file, e.g. system_current.txt.
+ currentApiFilePath android.OptionalPath
+
+ // The specification of API elements removed since the last release.
+ removedApiFilePath android.OptionalPath
+
+ // The stubs source jar.
+ stubsSrcJar android.OptionalPath
}
func (paths *scopePaths) extractStubsLibraryInfoFromDependency(dep android.Module) error {
@@ -373,23 +489,211 @@ func (paths *scopePaths) extractStubsLibraryInfoFromDependency(dep android.Modul
}
}
-func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(dep android.Module) error {
- if provider, ok := dep.(ApiStubsProvider); ok {
- paths.currentApiFilePath = provider.ApiFilePath()
- paths.removedApiFilePath = provider.RemovedApiFilePath()
- paths.stubsSrcJar = provider.StubsSrcJar()
+func (paths *scopePaths) treatDepAsApiStubsProvider(dep android.Module, action func(provider ApiStubsProvider)) error {
+ if apiStubsProvider, ok := dep.(ApiStubsProvider); ok {
+ action(apiStubsProvider)
return nil
} else {
return fmt.Errorf("expected module that implements ApiStubsProvider, e.g. droidstubs")
}
}
+func (paths *scopePaths) treatDepAsApiStubsSrcProvider(dep android.Module, action func(provider ApiStubsSrcProvider)) error {
+ if apiStubsProvider, ok := dep.(ApiStubsSrcProvider); ok {
+ action(apiStubsProvider)
+ return nil
+ } else {
+ return fmt.Errorf("expected module that implements ApiStubsSrcProvider, e.g. droidstubs")
+ }
+}
+
+func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider) {
+ paths.currentApiFilePath = android.OptionalPathForPath(provider.ApiFilePath())
+ paths.removedApiFilePath = android.OptionalPathForPath(provider.RemovedApiFilePath())
+}
+
+func (paths *scopePaths) extractApiInfoFromDep(dep android.Module) error {
+ return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) {
+ paths.extractApiInfoFromApiStubsProvider(provider)
+ })
+}
+
+func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider ApiStubsSrcProvider) {
+ paths.stubsSrcJar = android.OptionalPathForPath(provider.StubsSrcJar())
+}
+
+func (paths *scopePaths) extractStubsSourceInfoFromDep(dep android.Module) error {
+ return paths.treatDepAsApiStubsSrcProvider(dep, func(provider ApiStubsSrcProvider) {
+ paths.extractStubsSourceInfoFromApiStubsProviders(provider)
+ })
+}
+
+func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(dep android.Module) error {
+ return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) {
+ paths.extractApiInfoFromApiStubsProvider(provider)
+ paths.extractStubsSourceInfoFromApiStubsProviders(provider)
+ })
+}
+
+type commonToSdkLibraryAndImportProperties struct {
+ // The naming scheme to use for the components that this module creates.
+ //
+ // If not specified then it defaults to "default". The other allowable value is
+ // "framework-modules" which matches the scheme currently used by framework modules
+ // for the equivalent components represented as separate Soong modules.
+ //
+ // This is a temporary mechanism to simplify conversion from separate modules for each
+ // component that follow a different naming pattern to the default one.
+ //
+ // TODO(b/155480189) - Remove once naming inconsistencies have been resolved.
+ Naming_scheme *string
+
+ // Specifies whether this module can be used as an Android shared library; defaults
+ // to true.
+ //
+ // An Android shared library is one that can be referenced in a <uses-library> element
+ // in an AndroidManifest.xml.
+ Shared_library *bool
+}
+
// Common code between sdk library and sdk library import
type commonToSdkLibraryAndImport struct {
+ moduleBase *android.ModuleBase
+
scopePaths map[*apiScope]*scopePaths
+
+ namingScheme sdkLibraryComponentNamingScheme
+
+ commonSdkLibraryProperties commonToSdkLibraryAndImportProperties
+
+ // Functionality related to this being used as a component of a java_sdk_library.
+ EmbeddableSdkLibraryComponent
+}
+
+func (c *commonToSdkLibraryAndImport) initCommon(moduleBase *android.ModuleBase) {
+ c.moduleBase = moduleBase
+
+ moduleBase.AddProperties(&c.commonSdkLibraryProperties)
+
+ // Initialize this as an sdk library component.
+ c.initSdkLibraryComponent(moduleBase)
+}
+
+func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android.DefaultableHookContext) bool {
+ schemeProperty := proptools.StringDefault(c.commonSdkLibraryProperties.Naming_scheme, "default")
+ switch schemeProperty {
+ case "default":
+ c.namingScheme = &defaultNamingScheme{}
+ case "framework-modules":
+ c.namingScheme = &frameworkModulesNamingScheme{}
+ default:
+ ctx.PropertyErrorf("naming_scheme", "expected 'default' but was %q", schemeProperty)
+ return false
+ }
+
+ // Only track this sdk library if this can be used as a shared library.
+ if c.sharedLibrary() {
+ // Use the name specified in the module definition as the owner.
+ c.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack = proptools.StringPtr(c.moduleBase.BaseModuleName())
+ }
+
+ return true
+}
+
+// Name of the java_library module that compiles the stubs source.
+func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string {
+ return c.namingScheme.stubsLibraryModuleName(apiScope, c.moduleBase.BaseModuleName())
+}
+
+// Name of the droidstubs module that generates the stubs source and may also
+// generate/check the API.
+func (c *commonToSdkLibraryAndImport) stubsSourceModuleName(apiScope *apiScope) string {
+ return c.namingScheme.stubsSourceModuleName(apiScope, c.moduleBase.BaseModuleName())
+}
+
+// Name of the droidstubs module that generates/checks the API. Only used if it
+// requires different arts to the stubs source generating module.
+func (c *commonToSdkLibraryAndImport) apiModuleName(apiScope *apiScope) string {
+ return c.namingScheme.apiModuleName(apiScope, c.moduleBase.BaseModuleName())
}
-func (c *commonToSdkLibraryAndImport) getScopePaths(scope *apiScope) *scopePaths {
+// The component names for different outputs of the java_sdk_library.
+//
+// They are similar to the names used for the child modules it creates
+const (
+ stubsSourceComponentName = "stubs.source"
+
+ apiTxtComponentName = "api.txt"
+
+ removedApiTxtComponentName = "removed-api.txt"
+)
+
+// A regular expression to match tags that reference a specific stubs component.
+//
+// It will only match if given a valid scope and a valid component. It is verfy strict
+// to ensure it does not accidentally match a similar looking tag that should be processed
+// by the embedded Library.
+var tagSplitter = func() *regexp.Regexp {
+ // Given a list of literal string items returns a regular expression that will
+ // match any one of the items.
+ choice := func(items ...string) string {
+ return `\Q` + strings.Join(items, `\E|\Q`) + `\E`
+ }
+
+ // Regular expression to match one of the scopes.
+ scopesRegexp := choice(allScopeNames...)
+
+ // Regular expression to match one of the components.
+ componentsRegexp := choice(stubsSourceComponentName, apiTxtComponentName, removedApiTxtComponentName)
+
+ // Regular expression to match any combination of one scope and one component.
+ return regexp.MustCompile(fmt.Sprintf(`^\.(%s)\.(%s)$`, scopesRegexp, componentsRegexp))
+}()
+
+// For OutputFileProducer interface
+//
+// .<scope>.stubs.source
+// .<scope>.api.txt
+// .<scope>.removed-api.txt
+func (c *commonToSdkLibraryAndImport) commonOutputFiles(tag string) (android.Paths, error) {
+ if groups := tagSplitter.FindStringSubmatch(tag); groups != nil {
+ scopeName := groups[1]
+ component := groups[2]
+
+ if scope, ok := scopeByName[scopeName]; ok {
+ paths := c.findScopePaths(scope)
+ if paths == nil {
+ return nil, fmt.Errorf("%q does not provide api scope %s", c.moduleBase.BaseModuleName(), scopeName)
+ }
+
+ switch component {
+ case stubsSourceComponentName:
+ if paths.stubsSrcJar.Valid() {
+ return android.Paths{paths.stubsSrcJar.Path()}, nil
+ }
+
+ case apiTxtComponentName:
+ if paths.currentApiFilePath.Valid() {
+ return android.Paths{paths.currentApiFilePath.Path()}, nil
+ }
+
+ case removedApiTxtComponentName:
+ if paths.removedApiFilePath.Valid() {
+ return android.Paths{paths.removedApiFilePath.Path()}, nil
+ }
+ }
+
+ return nil, fmt.Errorf("%s not available for api scope %s", component, scopeName)
+ } else {
+ return nil, fmt.Errorf("unknown scope %s in %s", scope, tag)
+ }
+
+ } else {
+ return nil, nil
+ }
+}
+
+func (c *commonToSdkLibraryAndImport) getScopePathsCreateIfNeeded(scope *apiScope) *scopePaths {
if c.scopePaths == nil {
c.scopePaths = make(map[*apiScope]*scopePaths)
}
@@ -402,6 +706,147 @@ func (c *commonToSdkLibraryAndImport) getScopePaths(scope *apiScope) *scopePaths
return paths
}
+func (c *commonToSdkLibraryAndImport) findScopePaths(scope *apiScope) *scopePaths {
+ if c.scopePaths == nil {
+ return nil
+ }
+
+ return c.scopePaths[scope]
+}
+
+// If this does not support the requested api scope then find the closest available
+// scope it does support. Returns nil if no such scope is available.
+func (c *commonToSdkLibraryAndImport) findClosestScopePath(scope *apiScope) *scopePaths {
+ for s := scope; s != nil; s = s.extends {
+ if paths := c.findScopePaths(s); paths != nil {
+ return paths
+ }
+ }
+
+ // This should never happen outside tests as public should be the base scope for every
+ // scope and is enabled by default.
+ return nil
+}
+
+func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
+
+ // If a specific numeric version has been requested then use prebuilt versions of the sdk.
+ if sdkVersion.version.isNumbered() {
+ return PrebuiltJars(ctx, c.moduleBase.BaseModuleName(), sdkVersion)
+ }
+
+ var apiScope *apiScope
+ switch sdkVersion.kind {
+ case sdkSystem:
+ apiScope = apiScopeSystem
+ case sdkModule:
+ apiScope = apiScopeModuleLib
+ case sdkTest:
+ apiScope = apiScopeTest
+ default:
+ apiScope = apiScopePublic
+ }
+
+ paths := c.findClosestScopePath(apiScope)
+ if paths == nil {
+ var scopes []string
+ for _, s := range allApiScopes {
+ if c.findScopePaths(s) != nil {
+ scopes = append(scopes, s.name)
+ }
+ }
+ ctx.ModuleErrorf("requires api scope %s from %s but it only has %q available", apiScope.name, c.moduleBase.BaseModuleName(), scopes)
+ return nil
+ }
+
+ return paths.stubsHeaderPath
+}
+
+func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} {
+ componentProps := &struct {
+ SdkLibraryToImplicitlyTrack *string
+ }{}
+
+ if c.sharedLibrary() {
+ // Mark the stubs library as being components of this java_sdk_library so that
+ // any app that includes code which depends (directly or indirectly) on the stubs
+ // library will have the appropriate <uses-library> invocation inserted into its
+ // manifest if necessary.
+ componentProps.SdkLibraryToImplicitlyTrack = proptools.StringPtr(c.moduleBase.BaseModuleName())
+ }
+
+ return componentProps
+}
+
+// Check if this can be used as a shared library.
+func (c *commonToSdkLibraryAndImport) sharedLibrary() bool {
+ return proptools.BoolDefault(c.commonSdkLibraryProperties.Shared_library, true)
+}
+
+// Properties related to the use of a module as an component of a java_sdk_library.
+type SdkLibraryComponentProperties struct {
+
+ // The name of the java_sdk_library/_import to add to a <uses-library> entry
+ // in the AndroidManifest.xml of any Android app that includes code that references
+ // this module. If not set then no java_sdk_library/_import is tracked.
+ SdkLibraryToImplicitlyTrack *string `blueprint:"mutated"`
+}
+
+// Structure to be embedded in a module struct that needs to support the
+// SdkLibraryComponentDependency interface.
+type EmbeddableSdkLibraryComponent struct {
+ sdkLibraryComponentProperties SdkLibraryComponentProperties
+}
+
+func (e *EmbeddableSdkLibraryComponent) initSdkLibraryComponent(moduleBase *android.ModuleBase) {
+ moduleBase.AddProperties(&e.sdkLibraryComponentProperties)
+}
+
+// to satisfy SdkLibraryComponentDependency
+func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() []string {
+ if e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack != nil {
+ return []string{*e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack}
+ }
+ return nil
+}
+
+// Implemented by modules that are (or possibly could be) a component of a java_sdk_library
+// (including the java_sdk_library) itself.
+type SdkLibraryComponentDependency interface {
+ // 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 an array containing 0 or 1 items rather than a *string to make it easier
+ // to append this to the list of exported sdk libraries.
+ OptionalImplicitSdkLibrary() []string
+}
+
+// Make sure that all the module types that are components of java_sdk_library/_import
+// and which can be referenced (directly or indirectly) from an android app implement
+// the SdkLibraryComponentDependency interface.
+var _ SdkLibraryComponentDependency = (*Library)(nil)
+var _ SdkLibraryComponentDependency = (*Import)(nil)
+var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil)
+var _ SdkLibraryComponentDependency = (*sdkLibraryImport)(nil)
+
+// Provides access to sdk_version related header and implentation jars.
+type SdkLibraryDependency interface {
+ SdkLibraryComponentDependency
+
+ // Get the header jars appropriate for the supplied sdk_version.
+ //
+ // These are turbine generated jars so they only change if the externals of the
+ // class changes but it does not contain and implementation or JavaDoc.
+ SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths
+
+ // Get the implementation jars appropriate for the supplied sdk version.
+ //
+ // These are either the implementation jar for the whole sdk library or the implementation
+ // jars for the stubs. The latter should only be needed when generating JavaDoc as otherwise
+ // they are identical to the corresponding header jars.
+ SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths
+}
+
type SdkLibrary struct {
Library
@@ -477,26 +922,51 @@ func IsXmlPermissionsFileDepTag(depTag blueprint.DependencyTag) bool {
return false
}
+var implLibraryTag = dependencyTag{name: "impl-library"}
+
func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
for _, apiScope := range module.getGeneratedApiScopes(ctx) {
// Add dependencies to the stubs library
- ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsName(apiScope))
+ ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope))
- // And the stubs source and api files
- ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceName(apiScope))
+ // If the stubs source and API cannot be generated together then add an additional dependency on
+ // the API module.
+ if apiScope.createStubsSourceAndApiTogether {
+ // Add a dependency on the stubs source in order to access both stubs source and api information.
+ ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope))
+ } else {
+ // Add separate dependencies on the creators of the stubs source files and the API.
+ ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, module.stubsSourceModuleName(apiScope))
+ ctx.AddVariationDependencies(nil, apiScope.apiFileTag, module.apiModuleName(apiScope))
+ }
}
- if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
- // Add dependency to the rule for generating the xml permissions file
- ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlFileName())
+ if module.requiresRuntimeImplementationLibrary() {
+ // Add dependency to the rule for generating the implementation library.
+ ctx.AddDependency(module, implLibraryTag, module.implLibraryModuleName())
+
+ if module.sharedLibrary() {
+ // Add dependency to the rule for generating the xml permissions file
+ ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlFileName())
+ }
+
+ // Only add the deps for the library if it is actually going to be built.
+ module.Library.deps(ctx)
}
+}
- module.Library.deps(ctx)
+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 {
+ return paths, err
+ }
}
func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- // Don't build an implementation library if this is api only.
- if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
+ // Only build an implementation library if required.
+ if module.requiresRuntimeImplementationLibrary() {
module.Library.GenerateAndroidBuildActions(ctx)
}
@@ -509,7 +979,7 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext)
// Extract information from any of the scope specific dependencies.
if scopeTag, ok := tag.(scopeDependencyTag); ok {
apiScope := scopeTag.apiScope
- scopePaths := module.getScopePaths(apiScope)
+ scopePaths := module.getScopePathsCreateIfNeeded(apiScope)
// Extract information from the dependency. The exact information extracted
// is determined by the nature of the dependency which is determined by the tag.
@@ -519,7 +989,7 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext)
}
func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries {
- if proptools.Bool(module.sdkLibraryProperties.Api_only) {
+ if !module.requiresRuntimeImplementationLibrary() {
return nil
}
entriesList := module.Library.AndroidMkEntries()
@@ -528,20 +998,9 @@ func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries {
return entriesList
}
-// Name of the java_library module that compiles the stubs source.
-func (module *SdkLibrary) stubsName(apiScope *apiScope) string {
- return apiScope.stubsModuleName(module.BaseModuleName())
-}
-
-// // Name of the droidstubs module that generates the stubs source and
-// generates/checks the API.
-func (module *SdkLibrary) stubsSourceName(apiScope *apiScope) string {
- return apiScope.stubsSourceModuleName(module.BaseModuleName())
-}
-
// Module name of the runtime implementation library
-func (module *SdkLibrary) implName() string {
- return module.BaseModuleName()
+func (module *SdkLibrary) implLibraryModuleName() string {
+ return module.BaseModuleName() + ".impl"
}
// Module name of the XML file for the lib
@@ -561,7 +1020,12 @@ func (module *SdkLibrary) apiDistPath(apiScope *apiScope) string {
}
// Get the sdk version for use when compiling the stubs library.
-func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) string {
+func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.EarlyModuleContext, apiScope *apiScope) string {
+ scopeProperties := module.scopeToProperties[apiScope]
+ if scopeProperties.Sdk_version != nil {
+ return proptools.String(scopeProperties.Sdk_version)
+ }
+
sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
if sdkDep.hasStandardLibs() {
// If building against a standard sdk then use the sdk version appropriate for the scope.
@@ -580,24 +1044,41 @@ func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope *apiScope) stri
return ":" + module.BaseModuleName() + "-removed.api." + apiScope.name + ".latest"
}
+// Creates the implementation java library
+func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) {
+ props := struct {
+ Name *string
+ Visibility []string
+ }{
+ Name: proptools.StringPtr(module.implLibraryModuleName()),
+ Visibility: module.sdkLibraryProperties.Impl_library_visibility,
+ }
+
+ properties := []interface{}{
+ &module.properties,
+ &module.protoProperties,
+ &module.deviceProperties,
+ &module.dexpreoptProperties,
+ &props,
+ module.sdkComponentPropertiesForChildLibrary(),
+ }
+ mctx.CreateModule(LibraryFactory, properties...)
+}
+
// Creates a static java library that has API stubs
func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
props := struct {
- Name *string
- Visibility []string
- Srcs []string
- Installable *bool
- Sdk_version *string
- System_modules *string
- Patch_module *string
- Libs []string
- Soc_specific *bool
- Device_specific *bool
- Product_specific *bool
- System_ext_specific *bool
- Compile_dex *bool
- Java_version *string
- Product_variables struct {
+ Name *string
+ Visibility []string
+ Srcs []string
+ Installable *bool
+ Sdk_version *string
+ System_modules *string
+ Patch_module *string
+ Libs []string
+ Compile_dex *bool
+ Java_version *string
+ Product_variables struct {
Pdk struct {
Enabled *bool
}
@@ -614,7 +1095,7 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext
}
}{}
- props.Name = proptools.StringPtr(module.stubsName(apiScope))
+ props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
// If stubs_library_visibility is not set then the created module will use the
// visibility of this module.
@@ -622,30 +1103,21 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext
props.Visibility = visibility
// sources are generated from the droiddoc
- props.Srcs = []string{":" + module.stubsSourceName(apiScope)}
+ props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)}
sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
props.Sdk_version = proptools.StringPtr(sdkVersion)
- props.System_modules = module.Library.Module.deviceProperties.System_modules
- props.Patch_module = module.Library.Module.properties.Patch_module
+ props.System_modules = module.deviceProperties.System_modules
+ props.Patch_module = module.properties.Patch_module
props.Installable = proptools.BoolPtr(false)
props.Libs = module.sdkLibraryProperties.Stub_only_libs
props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false)
- props.Openjdk9.Srcs = module.Library.Module.properties.Openjdk9.Srcs
- props.Openjdk9.Javacflags = module.Library.Module.properties.Openjdk9.Javacflags
- props.Java_version = module.Library.Module.properties.Java_version
- if module.Library.Module.deviceProperties.Compile_dex != nil {
- props.Compile_dex = module.Library.Module.deviceProperties.Compile_dex
+ props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs
+ props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags
+ props.Java_version = module.properties.Java_version
+ if module.deviceProperties.Compile_dex != nil {
+ props.Compile_dex = module.deviceProperties.Compile_dex
}
- if module.SocSpecific() {
- props.Soc_specific = proptools.BoolPtr(true)
- } else if module.DeviceSpecific() {
- props.Device_specific = proptools.BoolPtr(true)
- } else if module.ProductSpecific() {
- props.Product_specific = proptools.BoolPtr(true)
- } else if module.SystemExtSpecific() {
- props.System_ext_specific = proptools.BoolPtr(true)
- }
// Dist the class jar artifact for sdk builds.
if !Bool(module.sdkLibraryProperties.No_dist) {
props.Dist.Targets = []string{"sdk", "win_sdk"}
@@ -654,12 +1126,12 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext
props.Dist.Tag = proptools.StringPtr(".jar")
}
- mctx.CreateModule(LibraryFactory, &props)
+ mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
}
// Creates a droidstubs module that creates stubs source files from the given full source
// files and also updates and checks the API specification files.
-func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope) {
+func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, createStubSources, createApi bool, scopeSpecificDroidstubsArgs []string) {
props := struct {
Name *string
Visibility []string
@@ -673,10 +1145,17 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC
Java_version *string
Merge_annotations_dirs []string
Merge_inclusion_annotations_dirs []string
+ Generate_stubs *bool
Check_api struct {
Current ApiToCheck
Last_released ApiToCheck
Ignore_missing_latest_api *bool
+
+ Api_lint struct {
+ Enabled *bool
+ New_since *string
+ Baseline_file *string
+ }
}
Aidl struct {
Include_dirs []string
@@ -695,24 +1174,24 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC
// * system_modules
// * libs (static_libs/libs)
- props.Name = proptools.StringPtr(module.stubsSourceName(apiScope))
+ props.Name = proptools.StringPtr(name)
// If stubs_source_visibility is not set then the created module will use the
// visibility of this module.
visibility := module.sdkLibraryProperties.Stubs_source_visibility
props.Visibility = visibility
- props.Srcs = append(props.Srcs, module.Library.Module.properties.Srcs...)
- props.Sdk_version = module.Library.Module.deviceProperties.Sdk_version
- props.System_modules = module.Library.Module.deviceProperties.System_modules
+ props.Srcs = append(props.Srcs, module.properties.Srcs...)
+ props.Sdk_version = module.deviceProperties.Sdk_version
+ props.System_modules = module.deviceProperties.System_modules
props.Installable = proptools.BoolPtr(false)
// A droiddoc module has only one Libs property and doesn't distinguish between
// shared libs and static libs. So we need to add both of these libs to Libs property.
- props.Libs = module.Library.Module.properties.Libs
- props.Libs = append(props.Libs, module.Library.Module.properties.Static_libs...)
- props.Aidl.Include_dirs = module.Library.Module.deviceProperties.Aidl.Include_dirs
- props.Aidl.Local_include_dirs = module.Library.Module.deviceProperties.Aidl.Local_include_dirs
- props.Java_version = module.Library.Module.properties.Java_version
+ props.Libs = module.properties.Libs
+ props.Libs = append(props.Libs, module.properties.Static_libs...)
+ props.Aidl.Include_dirs = module.deviceProperties.Aidl.Include_dirs
+ props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs
+ props.Java_version = module.properties.Java_version
props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs
props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs
@@ -739,38 +1218,64 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC
}
droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
+ if !createStubSources {
+ // Stubs are not required.
+ props.Generate_stubs = proptools.BoolPtr(false)
+ }
+
// Add in scope specific arguments.
- droidstubsArgs = append(droidstubsArgs, apiScope.droidstubsArgs...)
+ droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...)
props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
- // List of APIs identified from the provided source files are created. They are later
- // compared against to the not-yet-released (a.k.a current) list of APIs and to the
- // last-released (a.k.a numbered) list of API.
- currentApiFileName := apiScope.apiFilePrefix + "current.txt"
- removedApiFileName := apiScope.apiFilePrefix + "removed.txt"
- apiDir := module.getApiDir()
- currentApiFileName = path.Join(apiDir, currentApiFileName)
- removedApiFileName = path.Join(apiDir, removedApiFileName)
-
- // check against the not-yet-release API
- props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
- props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
-
- if !apiScope.unstable {
- // check against the latest released API
- props.Check_api.Last_released.Api_file = proptools.StringPtr(
- module.latestApiFilegroupName(apiScope))
- props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
- module.latestRemovedApiFilegroupName(apiScope))
- props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
- }
+ if createApi {
+ // List of APIs identified from the provided source files are created. They are later
+ // compared against to the not-yet-released (a.k.a current) list of APIs and to the
+ // last-released (a.k.a numbered) list of API.
+ currentApiFileName := apiScope.apiFilePrefix + "current.txt"
+ removedApiFileName := apiScope.apiFilePrefix + "removed.txt"
+ apiDir := module.getApiDir()
+ currentApiFileName = path.Join(apiDir, currentApiFileName)
+ removedApiFileName = path.Join(apiDir, removedApiFileName)
+
+ // check against the not-yet-release API
+ props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
+ props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
+
+ if !apiScope.unstable {
+ // check against the latest released API
+ latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
+ props.Check_api.Last_released.Api_file = latestApiFilegroupName
+ props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
+ module.latestRemovedApiFilegroupName(apiScope))
+ props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
+
+ if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) {
+ // Enable api lint.
+ props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true)
+ props.Check_api.Api_lint.New_since = latestApiFilegroupName
+
+ // If it exists then pass a lint-baseline.txt through to droidstubs.
+ baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt")
+ baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath)
+ paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil)
+ if err != nil {
+ mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err)
+ }
+ if len(paths) == 1 {
+ props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath)
+ } else if len(paths) != 0 {
+ mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths)
+ }
+ }
+ }
- // Dist the api txt artifact for sdk builds.
- if !Bool(module.sdkLibraryProperties.No_dist) {
- props.Dist.Targets = []string{"sdk", "win_sdk"}
- props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.txt", module.BaseModuleName()))
- props.Dist.Dir = proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
+ // Dist the api txt artifact for sdk builds.
+ if !Bool(module.sdkLibraryProperties.No_dist) {
+ props.Dist.Targets = []string{"sdk", "win_sdk"}
+ props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.txt", module.BaseModuleName()))
+ props.Dist.Dir = proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
+ }
}
mctx.CreateModule(DroidstubsFactory, &props)
@@ -787,29 +1292,15 @@ func (module *SdkLibrary) DepIsInSameApex(mctx android.BaseModuleContext, dep an
// Creates the xml file that publicizes the runtime library
func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) {
props := struct {
- Name *string
- Lib_name *string
- Soc_specific *bool
- Device_specific *bool
- Product_specific *bool
- System_ext_specific *bool
- Apex_available []string
+ Name *string
+ Lib_name *string
+ Apex_available []string
}{
Name: proptools.StringPtr(module.xmlFileName()),
Lib_name: proptools.StringPtr(module.BaseModuleName()),
Apex_available: module.ApexProperties.Apex_available,
}
- if module.SocSpecific() {
- props.Soc_specific = proptools.BoolPtr(true)
- } else if module.DeviceSpecific() {
- props.Device_specific = proptools.BoolPtr(true)
- } else if module.ProductSpecific() {
- props.Product_specific = proptools.BoolPtr(true)
- } else if module.SystemExtSpecific() {
- props.System_ext_specific = proptools.BoolPtr(true)
- }
-
mctx.CreateModule(sdkLibraryXmlFactory, &props)
}
@@ -840,41 +1331,50 @@ func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s sdkSpec) and
return android.Paths{jarPath.Path()}
}
-func (module *SdkLibrary) sdkJars(
- ctx android.BaseModuleContext,
- sdkVersion sdkSpec,
- headerJars bool) android.Paths {
+// Get the apex name for module, "" if it is for platform.
+func getApexNameForModule(module android.Module) string {
+ if apex, ok := module.(android.ApexModule); ok {
+ return apex.ApexName()
+ }
- // If a specific numeric version has been requested then use prebuilt versions of the sdk.
- if sdkVersion.version.isNumbered() {
- return PrebuiltJars(ctx, module.BaseModuleName(), sdkVersion)
- } else {
- if !sdkVersion.specified() {
+ return ""
+}
+
+// Check to see if the other module is within the same named APEX as this module.
+//
+// If either this or the other module are on the platform then this will return
+// false.
+func (module *SdkLibrary) withinSameApexAs(other android.Module) bool {
+ name := module.ApexName()
+ return name != "" && getApexNameForModule(other) == name
+}
+
+func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths {
+ // If the client doesn't set sdk_version, but if this library prefers stubs over
+ // the impl library, let's provide the widest API surface possible. To do so,
+ // force override sdk_version to module_current so that the closest possible API
+ // surface could be found in selectHeaderJarsForSdkVersion
+ if module.defaultsToStubs() && !sdkVersion.specified() {
+ sdkVersion = sdkSpecFrom("module_current")
+ }
+
+ // Only provide access to the implementation library if it is actually built.
+ if module.requiresRuntimeImplementationLibrary() {
+ // Check any special cases for java_sdk_library.
+ //
+ // Only allow access to the implementation library in the following condition:
+ // * No sdk_version specified on the referencing module.
+ // * The referencing module is in the same apex as this.
+ if sdkVersion.kind == sdkPrivate || module.withinSameApexAs(ctx.Module()) {
if headerJars {
- return module.Library.HeaderJars()
+ return module.HeaderJars()
} else {
- return module.Library.ImplementationJars()
+ return module.ImplementationJars()
}
}
- var apiScope *apiScope
- switch sdkVersion.kind {
- case sdkSystem:
- apiScope = apiScopeSystem
- case sdkTest:
- apiScope = apiScopeTest
- case sdkPrivate:
- return module.Library.HeaderJars()
- default:
- apiScope = apiScopePublic
- }
-
- paths := module.getScopePaths(apiScope)
- if headerJars {
- return paths.stubsHeaderPath
- } else {
- return paths.stubsImplPath
- }
}
+
+ return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion)
}
// to satisfy SdkLibraryDependency interface
@@ -912,7 +1412,7 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont
return
}
- if len(module.Library.Module.properties.Srcs) == 0 {
+ if len(module.properties.Srcs) == 0 {
mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs")
return
}
@@ -958,13 +1458,40 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont
}
for _, scope := range generatedScopes {
+ stubsSourceArgs := scope.droidstubsArgsForGeneratingStubsSource
+ stubsSourceModuleName := module.stubsSourceModuleName(scope)
+
+ // If the args needed to generate the stubs and API are the same then they
+ // can be generated in a single invocation of metalava, otherwise they will
+ // need separate invocations.
+ if scope.createStubsSourceAndApiTogether {
+ // Use the stubs source name for legacy reasons.
+ module.createStubsSourcesAndApi(mctx, scope, stubsSourceModuleName, true, true, stubsSourceArgs)
+ } else {
+ module.createStubsSourcesAndApi(mctx, scope, stubsSourceModuleName, true, false, stubsSourceArgs)
+
+ apiArgs := scope.droidstubsArgsForGeneratingApi
+ apiName := module.apiModuleName(scope)
+ module.createStubsSourcesAndApi(mctx, scope, apiName, false, true, apiArgs)
+ }
+
module.createStubsLibrary(mctx, scope)
- module.createStubsSourcesAndApi(mctx, scope)
}
- if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
- // for runtime
- module.createXmlFile(mctx)
+ if module.requiresRuntimeImplementationLibrary() {
+ // Create child module to create an implementation library.
+ //
+ // This temporarily creates a second implementation library that can be explicitly
+ // referenced.
+ //
+ // TODO(b/156618935) - update comment once only one implementation library is created.
+ module.createImplLibrary(mctx)
+
+ // Only create an XML permissions file that declares the library as being usable
+ // as a shared library if required.
+ if module.sharedLibrary() {
+ module.createXmlFile(mctx)
+ }
// record java_sdk_library modules so that they are exported to make
javaSdkLibraries := javaSdkLibraries(mctx.Config())
@@ -977,16 +1504,77 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont
func (module *SdkLibrary) InitSdkLibraryProperties() {
module.AddProperties(
&module.sdkLibraryProperties,
- &module.Library.Module.properties,
- &module.Library.Module.dexpreoptProperties,
- &module.Library.Module.deviceProperties,
- &module.Library.Module.protoProperties,
+ &module.properties,
+ &module.dexpreoptProperties,
+ &module.deviceProperties,
+ &module.protoProperties,
)
- module.Library.Module.properties.Installable = proptools.BoolPtr(true)
- module.Library.Module.deviceProperties.IsSDKLibrary = true
+ module.initSdkLibraryComponent(&module.ModuleBase)
+
+ module.properties.Installable = proptools.BoolPtr(true)
+ module.deviceProperties.IsSDKLibrary = true
}
+func (module *SdkLibrary) requiresRuntimeImplementationLibrary() bool {
+ return !proptools.Bool(module.sdkLibraryProperties.Api_only)
+}
+
+func (module *SdkLibrary) defaultsToStubs() bool {
+ return proptools.Bool(module.sdkLibraryProperties.Default_to_stubs)
+}
+
+// Defines how to name the individual component modules the sdk library creates.
+type sdkLibraryComponentNamingScheme interface {
+ stubsLibraryModuleName(scope *apiScope, baseName string) string
+
+ stubsSourceModuleName(scope *apiScope, baseName string) string
+
+ apiModuleName(scope *apiScope, baseName string) string
+}
+
+type defaultNamingScheme struct {
+}
+
+func (s *defaultNamingScheme) stubsLibraryModuleName(scope *apiScope, baseName string) string {
+ return scope.stubsLibraryModuleName(baseName)
+}
+
+func (s *defaultNamingScheme) stubsSourceModuleName(scope *apiScope, baseName string) string {
+ return scope.stubsSourceModuleName(baseName)
+}
+
+func (s *defaultNamingScheme) apiModuleName(scope *apiScope, baseName string) string {
+ return scope.apiModuleName(baseName)
+}
+
+var _ sdkLibraryComponentNamingScheme = (*defaultNamingScheme)(nil)
+
+type frameworkModulesNamingScheme struct {
+}
+
+func (s *frameworkModulesNamingScheme) moduleSuffix(scope *apiScope) string {
+ suffix := scope.name
+ if scope == apiScopeModuleLib {
+ suffix = "module_libs_"
+ }
+ return suffix
+}
+
+func (s *frameworkModulesNamingScheme) stubsLibraryModuleName(scope *apiScope, baseName string) string {
+ return fmt.Sprintf("%s-stubs-%sapi", baseName, s.moduleSuffix(scope))
+}
+
+func (s *frameworkModulesNamingScheme) stubsSourceModuleName(scope *apiScope, baseName string) string {
+ return fmt.Sprintf("%s-stubs-srcs-%sapi", baseName, s.moduleSuffix(scope))
+}
+
+func (s *frameworkModulesNamingScheme) apiModuleName(scope *apiScope, baseName string) string {
+ return fmt.Sprintf("%s-api-%sapi", baseName, s.moduleSuffix(scope))
+}
+
+var _ sdkLibraryComponentNamingScheme = (*frameworkModulesNamingScheme)(nil)
+
// java_sdk_library is a special Java library that provides optional platform APIs to apps.
// In practice, it can be viewed as a combination of several modules: 1) stubs library that clients
// are linked against to, 2) droiddoc module that internally generates API stubs source files,
@@ -994,6 +1582,10 @@ func (module *SdkLibrary) InitSdkLibraryProperties() {
// the runtime lib to the classpath at runtime if requested via <uses-library>.
func SdkLibraryFactory() android.Module {
module := &SdkLibrary{}
+
+ // Initialize information common between source and prebuilt.
+ module.initCommon(&module.ModuleBase)
+
module.InitSdkLibraryProperties()
android.InitApexModule(module)
InitJavaModule(module, android.HostAndDeviceSupported)
@@ -1006,10 +1598,27 @@ func SdkLibraryFactory() android.Module {
module.scopeToProperties = scopeToProperties
// Add the properties containing visibility rules so that they are checked.
+ android.AddVisibilityProperty(module, "impl_library_visibility", &module.sdkLibraryProperties.Impl_library_visibility)
android.AddVisibilityProperty(module, "stubs_library_visibility", &module.sdkLibraryProperties.Stubs_library_visibility)
android.AddVisibilityProperty(module, "stubs_source_visibility", &module.sdkLibraryProperties.Stubs_source_visibility)
- module.SetDefaultableHook(func(ctx android.DefaultableHookContext) { module.CreateInternalModules(ctx) })
+ module.SetDefaultableHook(func(ctx android.DefaultableHookContext) {
+ // If no implementation is required then it cannot be used as a shared library
+ // either.
+ if !module.requiresRuntimeImplementationLibrary() {
+ // If shared_library has been explicitly set to true then it is incompatible
+ // with api_only: true.
+ if proptools.Bool(module.commonSdkLibraryProperties.Shared_library) {
+ ctx.PropertyErrorf("api_only/shared_library", "inconsistent settings, shared_library and api_only cannot both be true")
+ }
+ // Set shared_library: false.
+ module.commonSdkLibraryProperties.Shared_library = proptools.BoolPtr(false)
+ }
+
+ if module.initCommonAfterDefaultsApplied(ctx) {
+ module.CreateInternalModules(ctx)
+ }
+ })
return module
}
@@ -1030,10 +1639,10 @@ type sdkLibraryScopeProperties struct {
Stub_srcs []string `android:"path"`
// The current.txt
- Current_api string `android:"path"`
+ Current_api *string `android:"path"`
// The removed.txt
- Removed_api string `android:"path"`
+ Removed_api *string `android:"path"`
}
type sdkLibraryImportProperties struct {
@@ -1105,12 +1714,19 @@ func sdkLibraryImportFactory() android.Module {
module.scopeProperties = scopeToProperties
module.AddProperties(&module.properties, allScopeProperties)
+ // Initialize information common between source and prebuilt.
+ module.initCommon(&module.ModuleBase)
+
android.InitPrebuiltModule(module, &[]string{""})
android.InitApexModule(module)
android.InitSdkAwareModule(module)
InitJavaModule(module, android.HostAndDeviceSupported)
- module.SetDefaultableHook(func(mctx android.DefaultableHookContext) { module.createInternalModules(mctx) })
+ module.SetDefaultableHook(func(mctx android.DefaultableHookContext) {
+ if module.initCommonAfterDefaultsApplied(mctx) {
+ module.createInternalModules(mctx)
+ }
+ })
return module
}
@@ -1136,7 +1752,9 @@ func (module *sdkLibraryImport) createInternalModules(mctx android.DefaultableHo
module.createJavaImportForStubs(mctx, apiScope, scopeProperties)
- module.createPrebuiltStubsSources(mctx, apiScope, scopeProperties)
+ if len(scopeProperties.Stub_srcs) > 0 {
+ module.createPrebuiltStubsSources(mctx, apiScope, scopeProperties)
+ }
}
javaSdkLibraries := javaSdkLibraries(mctx.Config())
@@ -1148,47 +1766,37 @@ func (module *sdkLibraryImport) createInternalModules(mctx android.DefaultableHo
func (module *sdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
// Creates a java import for the jar with ".stubs" suffix
props := struct {
- Name *string
- Soc_specific *bool
- Device_specific *bool
- Product_specific *bool
- System_ext_specific *bool
- Sdk_version *string
- Libs []string
- Jars []string
- Prefer *bool
+ Name *string
+ Sdk_version *string
+ Libs []string
+ Jars []string
+ Prefer *bool
}{}
- props.Name = proptools.StringPtr(apiScope.stubsModuleName(module.BaseModuleName()))
+ props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
props.Sdk_version = scopeProperties.Sdk_version
// Prepend any of the libs from the legacy public properties to the libs for each of the
// scopes to avoid having to duplicate them in each scope.
props.Libs = append(module.properties.Libs, scopeProperties.Libs...)
props.Jars = scopeProperties.Jars
- if module.SocSpecific() {
- props.Soc_specific = proptools.BoolPtr(true)
- } else if module.DeviceSpecific() {
- props.Device_specific = proptools.BoolPtr(true)
- } else if module.ProductSpecific() {
- props.Product_specific = proptools.BoolPtr(true)
- } else if module.SystemExtSpecific() {
- props.System_ext_specific = proptools.BoolPtr(true)
- }
- // If the build should use prebuilt sdks then set prefer to true on the stubs library.
- // That will cause the prebuilt version of the stubs to override the source version.
- if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
- props.Prefer = proptools.BoolPtr(true)
- }
- mctx.CreateModule(ImportFactory, &props)
+
+ // The imports are preferred if the java_sdk_library_import is preferred.
+ props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer())
+
+ mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
}
func (module *sdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
props := struct {
- Name *string
- Srcs []string
+ Name *string
+ Srcs []string
+ Prefer *bool
}{}
- props.Name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()))
+ props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope))
props.Srcs = scopeProperties.Stub_srcs
mctx.CreateModule(PrebuiltStubsSourcesFactory, &props)
+
+ // The stubs source is preferred if the java_sdk_library_import is preferred.
+ props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer())
}
func (module *sdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -1198,46 +1806,49 @@ func (module *sdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext)
}
// Add dependencies to the prebuilt stubs library
- ctx.AddVariationDependencies(nil, apiScope.stubsTag, apiScope.stubsModuleName(module.BaseModuleName()))
+ ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope))
+
+ if len(scopeProperties.Stub_srcs) > 0 {
+ // Add dependencies to the prebuilt stubs source library
+ ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, module.stubsSourceModuleName(apiScope))
+ }
}
}
+func (module *sdkLibraryImport) OutputFiles(tag string) (android.Paths, error) {
+ return module.commonOutputFiles(tag)
+}
+
func (module *sdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- // Record the paths to the prebuilt stubs library.
+ // Record the paths to the prebuilt stubs library and stubs source.
ctx.VisitDirectDeps(func(to android.Module) {
tag := ctx.OtherModuleDependencyTag(to)
- if lib, ok := to.(Dependency); ok {
- if scopeTag, ok := tag.(scopeDependencyTag); ok {
- apiScope := scopeTag.apiScope
- scopePaths := module.getScopePaths(apiScope)
- scopePaths.stubsHeaderPath = lib.HeaderJars()
- }
+ // Extract information from any of the scope specific dependencies.
+ if scopeTag, ok := tag.(scopeDependencyTag); ok {
+ apiScope := scopeTag.apiScope
+ scopePaths := module.getScopePathsCreateIfNeeded(apiScope)
+
+ // Extract information from the dependency. The exact information extracted
+ // is determined by the nature of the dependency which is determined by the tag.
+ scopeTag.extractDepInfo(ctx, to, scopePaths)
}
})
-}
-func (module *sdkLibraryImport) sdkJars(
- ctx android.BaseModuleContext,
- sdkVersion sdkSpec) android.Paths {
-
- // If a specific numeric version has been requested then use prebuilt versions of the sdk.
- if sdkVersion.version.isNumbered() {
- return PrebuiltJars(ctx, module.BaseModuleName(), sdkVersion)
- }
+ // Populate the scope paths with information from the properties.
+ for apiScope, scopeProperties := range module.scopeProperties {
+ if len(scopeProperties.Jars) == 0 {
+ continue
+ }
- var apiScope *apiScope
- switch sdkVersion.kind {
- case sdkSystem:
- apiScope = apiScopeSystem
- case sdkTest:
- apiScope = apiScopeTest
- default:
- apiScope = apiScopePublic
+ paths := module.getScopePathsCreateIfNeeded(apiScope)
+ paths.currentApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Current_api)
+ paths.removedApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Removed_api)
}
+}
- paths := module.getScopePaths(apiScope)
- return paths.stubsHeaderPath
+func (module *sdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
+ return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion)
}
// to satisfy SdkLibraryDependency interface
@@ -1392,6 +2003,13 @@ type sdkLibrarySdkMemberProperties struct {
// The Java stubs source files.
Stub_srcs []string
+
+ // The naming scheme.
+ Naming_scheme *string
+
+ // True if the java_sdk_library_import is for a shared library, false
+ // otherwise.
+ Shared_library *bool
}
type scopeProperties struct {
@@ -1407,26 +2025,39 @@ func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMembe
s.Scopes = make(map[*apiScope]scopeProperties)
for _, apiScope := range allApiScopes {
- paths := sdk.getScopePaths(apiScope)
+ paths := sdk.findScopePaths(apiScope)
+ if paths == nil {
+ continue
+ }
+
jars := paths.stubsImplPath
if len(jars) > 0 {
properties := scopeProperties{}
properties.Jars = jars
- properties.SdkVersion = apiScope.sdkVersion
- properties.StubsSrcJar = paths.stubsSrcJar
- properties.CurrentApiFile = paths.currentApiFilePath
- properties.RemovedApiFile = paths.removedApiFilePath
+ properties.SdkVersion = sdk.sdkVersionForStubsLibrary(ctx.SdkModuleContext(), apiScope)
+ properties.StubsSrcJar = paths.stubsSrcJar.Path()
+ properties.CurrentApiFile = paths.currentApiFilePath.Path()
+ properties.RemovedApiFile = paths.removedApiFilePath.Path()
s.Scopes[apiScope] = properties
}
}
s.Libs = sdk.properties.Libs
+ s.Naming_scheme = sdk.commonSdkLibraryProperties.Naming_scheme
+ s.Shared_library = proptools.BoolPtr(sdk.sharedLibrary())
}
func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ if s.Naming_scheme != nil {
+ propertySet.AddProperty("naming_scheme", proptools.String(s.Naming_scheme))
+ }
+ if s.Shared_library != nil {
+ propertySet.AddProperty("shared_library", *s.Shared_library)
+ }
+
for _, apiScope := range allApiScopes {
if properties, ok := s.Scopes[apiScope]; ok {
- scopeSet := propertySet.AddPropertySet(apiScope.name)
+ scopeSet := propertySet.AddPropertySet(apiScope.propertyName)
scopeDir := filepath.Join("sdk_library", s.OsPrefix(), apiScope.name)
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 088db9e70..fb8646313 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -83,6 +83,16 @@ func TestClasspath(t *testing.T) {
},
{
+ name: "sdk v30",
+ properties: `sdk_version: "30",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_public_30_system_modules",
+ java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/30/public/framework.aidl",
+ },
+ {
+
name: "current",
properties: `sdk_version: "current",`,
bootclasspath: []string{"android_stubs_current", "core-lambda-stubs"},
@@ -110,6 +120,16 @@ func TestClasspath(t *testing.T) {
},
{
+ name: "system_30",
+ properties: `sdk_version: "system_30",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_public_30_system_modules",
+ java8classpath: []string{"prebuilts/sdk/30/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/30/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/30/public/framework.aidl",
+ },
+ {
+
name: "test_current",
properties: `sdk_version: "test_current",`,
bootclasspath: []string{"android_test_stubs_current", "core-lambda-stubs"},
@@ -176,12 +196,24 @@ func TestClasspath(t *testing.T) {
},
{
+ name: "unbundled sdk v30",
+ unbundled: true,
+ properties: `sdk_version: "30",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_public_30_system_modules",
+ java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/30/public/framework.aidl",
+ },
+ {
+
name: "unbundled current",
unbundled: true,
properties: `sdk_version: "current",`,
bootclasspath: []string{`""`},
- forces8: true,
+ 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",
},
@@ -189,27 +221,30 @@ func TestClasspath(t *testing.T) {
name: "pdk default",
pdk: true,
bootclasspath: []string{`""`},
- forces8: true,
- java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- aidl: "-pprebuilts/sdk/29/public/framework.aidl",
+ system: "sdk_public_30_system_modules",
+ java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/30/public/framework.aidl",
},
{
name: "pdk current",
pdk: true,
properties: `sdk_version: "current",`,
bootclasspath: []string{`""`},
- forces8: true,
- java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- aidl: "-pprebuilts/sdk/29/public/framework.aidl",
+ system: "sdk_public_30_system_modules",
+ java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/30/public/framework.aidl",
},
{
name: "pdk 29",
pdk: true,
properties: `sdk_version: "29",`,
bootclasspath: []string{`""`},
- forces8: true,
- java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- aidl: "-pprebuilts/sdk/29/public/framework.aidl",
+ system: "sdk_public_30_system_modules",
+ java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/30/public/framework.aidl",
},
{
name: "module_current",
@@ -292,12 +327,16 @@ func TestClasspath(t *testing.T) {
if testcase.system == "none" {
system = "--system=none"
} else if testcase.system != "" {
- system = "--system=" + filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system")
+ dir := ""
+ if strings.HasPrefix(testcase.system, "sdk_public_") {
+ dir = "prebuilts/sdk"
+ }
+ system = "--system=" + filepath.Join(buildDir, ".intermediates", dir, testcase.system, "android_common", "system")
// The module-relative parts of these paths are hardcoded in system_modules.go:
systemDeps = []string{
- filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system", "lib", "modules"),
- filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system", "lib", "jrt-fs.jar"),
- filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system", "release"),
+ filepath.Join(buildDir, ".intermediates", dir, testcase.system, "android_common", "system", "lib", "modules"),
+ filepath.Join(buildDir, ".intermediates", dir, testcase.system, "android_common", "system", "lib", "jrt-fs.jar"),
+ filepath.Join(buildDir, ".intermediates", dir, testcase.system, "android_common", "system", "release"),
}
}
diff --git a/java/testing.go b/java/testing.go
index 6929bb724..faf4d32b4 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -55,36 +55,54 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string
"assets_a/a": nil,
"assets_b/b": nil,
- "prebuilts/sdk/14/public/android.jar": nil,
- "prebuilts/sdk/14/public/framework.aidl": nil,
- "prebuilts/sdk/14/system/android.jar": nil,
- "prebuilts/sdk/17/public/android.jar": nil,
- "prebuilts/sdk/17/public/framework.aidl": nil,
- "prebuilts/sdk/17/system/android.jar": nil,
- "prebuilts/sdk/29/public/android.jar": nil,
- "prebuilts/sdk/29/public/framework.aidl": nil,
- "prebuilts/sdk/29/system/android.jar": nil,
- "prebuilts/sdk/29/system/foo.jar": nil,
- "prebuilts/sdk/current/core/android.jar": nil,
- "prebuilts/sdk/current/public/android.jar": nil,
- "prebuilts/sdk/current/public/framework.aidl": nil,
- "prebuilts/sdk/current/public/core.jar": nil,
- "prebuilts/sdk/current/system/android.jar": nil,
- "prebuilts/sdk/current/test/android.jar": nil,
- "prebuilts/sdk/28/public/api/foo.txt": nil,
- "prebuilts/sdk/28/system/api/foo.txt": nil,
- "prebuilts/sdk/28/test/api/foo.txt": nil,
- "prebuilts/sdk/28/public/api/foo-removed.txt": nil,
- "prebuilts/sdk/28/system/api/foo-removed.txt": nil,
- "prebuilts/sdk/28/test/api/foo-removed.txt": nil,
- "prebuilts/sdk/28/public/api/bar.txt": nil,
- "prebuilts/sdk/28/system/api/bar.txt": nil,
- "prebuilts/sdk/28/test/api/bar.txt": nil,
- "prebuilts/sdk/28/public/api/bar-removed.txt": nil,
- "prebuilts/sdk/28/system/api/bar-removed.txt": nil,
- "prebuilts/sdk/28/test/api/bar-removed.txt": nil,
- "prebuilts/sdk/tools/core-lambda-stubs.jar": nil,
- "prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "current"],}`),
+ "prebuilts/sdk/14/public/android.jar": nil,
+ "prebuilts/sdk/14/public/framework.aidl": nil,
+ "prebuilts/sdk/14/system/android.jar": nil,
+ "prebuilts/sdk/17/public/android.jar": nil,
+ "prebuilts/sdk/17/public/framework.aidl": nil,
+ "prebuilts/sdk/17/system/android.jar": nil,
+ "prebuilts/sdk/29/public/android.jar": nil,
+ "prebuilts/sdk/29/public/framework.aidl": nil,
+ "prebuilts/sdk/29/system/android.jar": nil,
+ "prebuilts/sdk/29/system/foo.jar": nil,
+ "prebuilts/sdk/30/public/android.jar": nil,
+ "prebuilts/sdk/30/public/framework.aidl": nil,
+ "prebuilts/sdk/30/system/android.jar": nil,
+ "prebuilts/sdk/30/system/foo.jar": nil,
+ "prebuilts/sdk/30/public/core-for-system-modules.jar": nil,
+ "prebuilts/sdk/current/core/android.jar": nil,
+ "prebuilts/sdk/current/public/android.jar": nil,
+ "prebuilts/sdk/current/public/framework.aidl": nil,
+ "prebuilts/sdk/current/public/core.jar": nil,
+ "prebuilts/sdk/current/public/core-for-system-modules.jar": nil,
+ "prebuilts/sdk/current/system/android.jar": nil,
+ "prebuilts/sdk/current/test/android.jar": nil,
+ "prebuilts/sdk/28/public/api/foo.txt": nil,
+ "prebuilts/sdk/28/system/api/foo.txt": nil,
+ "prebuilts/sdk/28/test/api/foo.txt": nil,
+ "prebuilts/sdk/28/public/api/foo-removed.txt": nil,
+ "prebuilts/sdk/28/system/api/foo-removed.txt": nil,
+ "prebuilts/sdk/28/test/api/foo-removed.txt": nil,
+ "prebuilts/sdk/28/public/api/bar.txt": nil,
+ "prebuilts/sdk/28/system/api/bar.txt": nil,
+ "prebuilts/sdk/28/test/api/bar.txt": nil,
+ "prebuilts/sdk/28/public/api/bar-removed.txt": nil,
+ "prebuilts/sdk/28/system/api/bar-removed.txt": nil,
+ "prebuilts/sdk/28/test/api/bar-removed.txt": nil,
+ "prebuilts/sdk/30/public/api/foo.txt": nil,
+ "prebuilts/sdk/30/system/api/foo.txt": nil,
+ "prebuilts/sdk/30/test/api/foo.txt": nil,
+ "prebuilts/sdk/30/public/api/foo-removed.txt": nil,
+ "prebuilts/sdk/30/system/api/foo-removed.txt": nil,
+ "prebuilts/sdk/30/test/api/foo-removed.txt": nil,
+ "prebuilts/sdk/30/public/api/bar.txt": nil,
+ "prebuilts/sdk/30/system/api/bar.txt": nil,
+ "prebuilts/sdk/30/test/api/bar.txt": nil,
+ "prebuilts/sdk/30/public/api/bar-removed.txt": nil,
+ "prebuilts/sdk/30/system/api/bar-removed.txt": nil,
+ "prebuilts/sdk/30/test/api/bar-removed.txt": nil,
+ "prebuilts/sdk/tools/core-lambda-stubs.jar": nil,
+ "prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "30", "current"],}`),
"prebuilts/apk/app.apk": nil,
"prebuilts/apk/app_arm.apk": nil,
@@ -92,6 +110,8 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string
"prebuilts/apk/app_xhdpi.apk": nil,
"prebuilts/apk/app_xxhdpi.apk": nil,
+ "prebuilts/apks/app.apks": nil,
+
// For framework-res, which is an implicit dependency for framework
"AndroidManifest.xml": nil,
"build/make/target/product/security/testkey": nil,
@@ -116,6 +136,7 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string
"cert/new_cert.x509.pem": nil,
"cert/new_cert.pk8": nil,
+ "lineage.bin": nil,
"testdata/data": nil,
@@ -209,6 +230,22 @@ func GatherRequiredDepsForTest() string {
system_modules: "core-platform-api-stubs-system-modules",
installable: true,
}
+
+ java_library {
+ name: "android.test.base",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "core-platform-api-stubs-system-modules",
+ installable: true,
+ }
+
+ java_library {
+ name: "android.test.mock",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "core-platform-api-stubs-system-modules",
+ installable: true,
+ }
`
systemModules := []string{