diff options
Diffstat (limited to 'java')
| -rw-r--r-- | java/Android.bp | 2 | ||||
| -rw-r--r-- | java/aar.go | 45 | ||||
| -rw-r--r-- | java/android_manifest.go | 9 | ||||
| -rw-r--r-- | java/androidmk.go | 63 | ||||
| -rw-r--r-- | java/androidmk_test.go | 190 | ||||
| -rwxr-xr-x | java/app.go | 202 | ||||
| -rw-r--r-- | java/app_test.go | 401 | ||||
| -rw-r--r-- | java/config/config.go | 32 | ||||
| -rw-r--r-- | java/config/makevars.go | 10 | ||||
| -rw-r--r-- | java/device_host_converter.go | 9 | ||||
| -rw-r--r-- | java/dex.go | 154 | ||||
| -rw-r--r-- | java/dexpreopt.go | 23 | ||||
| -rw-r--r-- | java/dexpreopt_bootjars.go | 224 | ||||
| -rw-r--r-- | java/dexpreopt_bootjars_test.go | 95 | ||||
| -rw-r--r-- | java/dexpreopt_config.go | 88 | ||||
| -rw-r--r-- | java/droiddoc.go | 169 | ||||
| -rw-r--r-- | java/hiddenapi.go | 4 | ||||
| -rw-r--r-- | java/hiddenapi_singleton.go | 38 | ||||
| -rw-r--r-- | java/java.go | 463 | ||||
| -rw-r--r-- | java/java_test.go | 320 | ||||
| -rw-r--r-- | java/jdeps.go | 1 | ||||
| -rw-r--r-- | java/kotlin.go | 70 | ||||
| -rw-r--r-- | java/legacy_core_platform_api_usage.go | 174 | ||||
| -rw-r--r-- | java/lint.go | 158 | ||||
| -rw-r--r-- | java/prebuilt_apis.go | 37 | ||||
| -rw-r--r-- | java/robolectric.go | 181 | ||||
| -rw-r--r-- | java/sdk.go | 115 | ||||
| -rw-r--r-- | java/sdk_library.go | 386 | ||||
| -rw-r--r-- | java/sdk_test.go | 81 | ||||
| -rw-r--r-- | java/testing.go | 68 |
30 files changed, 2690 insertions, 1122 deletions
diff --git a/java/Android.bp b/java/Android.bp index 1fda7f71d..e345014ce 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -10,6 +10,7 @@ bootstrap_go_package { "soong-dexpreopt", "soong-genrule", "soong-java-config", + "soong-python", "soong-remoteexec", "soong-tradefed", ], @@ -38,6 +39,7 @@ bootstrap_go_package { "java_resources.go", "kotlin.go", "lint.go", + "legacy_core_platform_api_usage.go", "platform_compat_config.go", "plugin.go", "prebuilt_apis.go", diff --git a/java/aar.go b/java/aar.go index 8dd752f12..0f5e30deb 100644 --- a/java/aar.go +++ b/java/aar.go @@ -20,6 +20,7 @@ import ( "strings" "android/soong/android" + "android/soong/dexpreopt" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -99,7 +100,7 @@ type aapt struct { useEmbeddedNativeLibs bool useEmbeddedDex bool usesNonSdkApis bool - sdkLibraries []string + sdkLibraries dexpreopt.LibraryPaths hasNoCode bool LoggingParent string resourceFiles android.Paths @@ -231,6 +232,8 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, ex transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags, sdkLibraries := aaptLibs(ctx, sdkContext) + a.sdkLibraries = sdkLibraries + // App manifest file manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile) @@ -357,7 +360,7 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, ex // aaptLibs collects libraries from dependencies and sdk_version and converts them into paths func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, transitiveStaticLibManifests android.Paths, - staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries []string) { + staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries dexpreopt.LibraryPaths) { var sharedLibs android.Paths @@ -366,6 +369,8 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati sharedLibs = append(sharedLibs, sdkDep.jars...) } + sdkLibraries = make(dexpreopt.LibraryPaths) + ctx.VisitDirectDeps(func(module android.Module) { var exportPackage android.Path aarDep, _ := module.(AndroidLibraryDependency) @@ -385,7 +390,8 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati // (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()...) + sdkLibraries.MaybeAddLibraryPath(ctx, component.OptionalImplicitSdkLibrary(), + component.DexJarBuildPath(), component.DexJarInstallPath()) } case frameworkResTag: @@ -393,11 +399,14 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati sharedLibs = append(sharedLibs, exportPackage) } case staticLibTag: + if dep, ok := module.(Dependency); ok { + sdkLibraries.AddLibraryPaths(dep.ExportedSdkLibs()) + } if exportPackage != nil { transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...) transitiveStaticLibs = append(transitiveStaticLibs, exportPackage) transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...) - sdkLibraries = append(sdkLibraries, aarDep.ExportedSdkLibs()...) + sdkLibraries.AddLibraryPaths(aarDep.ExportedSdkLibs()) if aarDep.ExportedAssets().Valid() { assets = append(assets, aarDep.ExportedAssets().Path()) } @@ -428,7 +437,6 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs) transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests) - sdkLibraries = android.FirstUniqueStrings(sdkLibraries) return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assets, deps, flags, sdkLibraries } @@ -465,8 +473,8 @@ func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.aapt.isLibrary = true - a.aapt.sdkLibraries = a.exportedSdkLibs a.aapt.buildActions(ctx, sdkContext(a)) + a.exportedSdkLibs = a.aapt.sdkLibraries ctx.CheckbuildFile(a.proguardOptionsFile) ctx.CheckbuildFile(a.exportPackage) @@ -625,7 +633,7 @@ func (a *AARImport) JacocoReportClassesFile() android.Path { } func (a *AARImport) DepsMutator(ctx android.BottomUpMutatorContext) { - if !ctx.Config().UnbundledBuildUsePrebuiltSdks() { + if !ctx.Config().AlwaysUsePrebuiltSdks() { sdkDep := decodeSdkDep(ctx, sdkContext(a)) if sdkDep.useModule && sdkDep.frameworkResModule != "" { ctx.AddVariationDependencies(nil, frameworkResTag, sdkDep.frameworkResModule) @@ -641,9 +649,11 @@ func (a *AARImport) DepsMutator(ctx android.BottomUpMutatorContext) { var unzipAAR = pctx.AndroidStaticRule("unzipAAR", blueprint.RuleParams{ Command: `rm -rf $outDir && mkdir -p $outDir && ` + - `unzip -qoDD -d $outDir $in && rm -rf $outDir/res && touch $out`, + `unzip -qoDD -d $outDir $in && rm -rf $outDir/res && touch $out && ` + + `${config.MergeZipsCmd} $combinedClassesJar $$(ls $outDir/classes.jar 2> /dev/null) $$(ls $outDir/libs/*.jar 2> /dev/null)`, + CommandDeps: []string{"${config.MergeZipsCmd}"}, }, - "outDir") + "outDir", "combinedClassesJar") func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { if len(a.properties.Aars) != 1 { @@ -661,7 +671,7 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { } extractedAARDir := android.PathForModuleOut(ctx, "aar") - a.classpathFile = extractedAARDir.Join(ctx, "classes.jar") + a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar") a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt") a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml") @@ -671,7 +681,8 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { Outputs: android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest}, Description: "unzip AAR", Args: map[string]string{ - "outDir": extractedAARDir.String(), + "outDir": extractedAARDir.String(), + "combinedClassesJar": a.classpathFile.String(), }, }) @@ -734,7 +745,11 @@ func (a *AARImport) ImplementationAndResourcesJars() android.Paths { return android.Paths{a.classpathFile} } -func (a *AARImport) DexJar() android.Path { +func (a *AARImport) DexJarBuildPath() android.Path { + return nil +} + +func (a *AARImport) DexJarInstallPath() android.Path { return nil } @@ -742,7 +757,7 @@ func (a *AARImport) AidlIncludeDirs() android.Paths { return nil } -func (a *AARImport) ExportedSdkLibs() []string { +func (a *AARImport) ExportedSdkLibs() dexpreopt.LibraryPaths { return nil } @@ -758,6 +773,10 @@ func (a *AARImport) DepIsInSameApex(ctx android.BaseModuleContext, dep android.M return a.depIsInSameApex(ctx, dep) } +func (g *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + return nil +} + var _ android.PrebuiltInterface = (*Import)(nil) // android_library_import imports an `.aar` file into the build graph as if it was built with android_library. diff --git a/java/android_manifest.go b/java/android_manifest.go index 8280cb1b1..f45ebe8d5 100644 --- a/java/android_manifest.go +++ b/java/android_manifest.go @@ -21,6 +21,7 @@ import ( "github.com/google/blueprint" "android/soong/android" + "android/soong/dexpreopt" ) var manifestFixerRule = pctx.AndroidStaticRule("manifestFixer", @@ -52,7 +53,7 @@ var optionalUsesLibs = []string{ } // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml -func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries []string, +func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries dexpreopt.LibraryPaths, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path { var args []string @@ -79,7 +80,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext args = append(args, "--use-embedded-dex") } - for _, usesLib := range sdkLibraries { + for usesLib, _ := range sdkLibraries { if inList(usesLib, optionalUsesLibs) { args = append(args, "--optional-uses-library", usesLib) } else { @@ -130,7 +131,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext }, }) - return fixedManifest + return fixedManifest.WithoutRel() } func manifestMerger(ctx android.ModuleContext, manifest android.Path, staticLibManifests android.Paths, @@ -155,5 +156,5 @@ func manifestMerger(ctx android.ModuleContext, manifest android.Path, staticLibM }, }) - return mergedManifest + return mergedManifest.WithoutRel() } diff --git a/java/androidmk.go b/java/androidmk.go index 62f97067c..2c02e5f38 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -91,7 +91,7 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { } else { mainEntries = android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", - DistFile: android.OptionalPathForPath(library.distFile), + DistFiles: library.distFiles, OutputFile: android.OptionalPathForPath(library.outputFile), Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ @@ -121,20 +121,17 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoReportClassesFile) } - entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.exportedSdkLibs...) + entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", android.SortedStringKeys(library.exportedSdkLibs)...) if len(library.additionalCheckedModules) != 0 { entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...) } - if library.proguardDictionary != nil { - entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.proguardDictionary) - } + entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_DICT", library.dexer.proguardDictionary) + entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", library.dexer.proguardUsageZip) entries.SetString("LOCAL_MODULE_STEM", library.Stem()) - entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", library.linter.outputs.transitiveHTMLZip) - entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", library.linter.outputs.transitiveTextZip) - entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", library.linter.outputs.transitiveXMLZip) + entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", library.linter.reports) }, }, } @@ -164,6 +161,7 @@ func (j *Test) AndroidMkEntries() []android.AndroidMkEntries { if j.testConfig != nil { entries.SetPath("LOCAL_FULL_TEST_CONFIG", j.testConfig) } + androidMkWriteExtraTestConfigs(j.extraTestConfigs, entries) androidMkWriteTestData(j.data, entries) if !BoolDefault(j.testProperties.Auto_gen_config, true) { entries.SetString("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", "true") @@ -173,6 +171,12 @@ func (j *Test) AndroidMkEntries() []android.AndroidMkEntries { return entriesList } +func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkEntries) { + if len(extraTestConfigs) > 0 { + entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...) + } +} + func (j *TestHelperLibrary) AndroidMkEntries() []android.AndroidMkEntries { entriesList := j.Library.AndroidMkEntries() entries := &entriesList[0] @@ -198,7 +202,7 @@ func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries { entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !Bool(prebuilt.properties.Installable)) entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile) - entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion().raw) + entries.SetString("LOCAL_SDK_VERSION", prebuilt.makeSdkVersion()) entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem()) }, }, @@ -334,9 +338,8 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { if app.jacocoReportClassesFile != nil { entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", app.jacocoReportClassesFile) } - if app.proguardDictionary != nil { - entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", app.proguardDictionary) - } + entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_DICT", app.dexer.proguardDictionary) + entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", app.dexer.proguardUsageZip) if app.Name() == "framework-res" { entries.SetString("LOCAL_MODULE_PATH", "$(TARGET_OUT_JAVA_LIBRARIES)") @@ -394,9 +397,7 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { entries.AddStrings("LOCAL_SOONG_BUILT_INSTALLED", extra.String()+":"+install) } - entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", app.linter.outputs.transitiveHTMLZip) - entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", app.linter.outputs.transitiveTextZip) - entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", app.linter.outputs.transitiveXMLZip) + entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", app.linter.reports) }, }, ExtraFooters: []android.AndroidMkExtraFootersFunc{ @@ -437,6 +438,7 @@ func (a *AndroidTest) AndroidMkEntries() []android.AndroidMkEntries { if a.testConfig != nil { entries.SetPath("LOCAL_FULL_TEST_CONFIG", a.testConfig) } + androidMkWriteExtraTestConfigs(a.extraTestConfigs, entries) androidMkWriteTestData(a.data, entries) }) @@ -545,14 +547,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") } }, }, @@ -565,15 +565,21 @@ func (dstubs *Droidstubs) AndroidMkEntries() []android.AndroidMkEntries { // are created in make if only the api txt file is being generated. This is // needed because an invalid output file would prevent the make entries from // being written. + // + // Note that dstubs.apiFile can be also be nil if WITHOUT_CHECKS_API is true. // TODO(b/146727827): Revert when we do not need to generate stubs and API separately. - distFile := android.OptionalPathForPath(dstubs.apiFile) + + var distFiles android.TaggedDistFiles + if dstubs.apiFile != nil { + distFiles = android.MakeDefaultDistFiles(dstubs.apiFile) + } outputFile := android.OptionalPathForPath(dstubs.stubsSrcJar) if !outputFile.Valid() { - outputFile = distFile + outputFile = android.OptionalPathForPath(dstubs.apiFile) } return []android.AndroidMkEntries{android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", - DistFile: distFile, + DistFiles: distFiles, OutputFile: outputFile, Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ @@ -669,6 +675,11 @@ func (dstubs *Droidstubs) AndroidMkEntries() []android.AndroidMkEntries { } func (a *AndroidAppImport) AndroidMkEntries() []android.AndroidMkEntries { + if !a.IsForPlatform() { + // The non-platform variant is placed inside APEX. No reason to + // make it available to Make. + return nil + } return []android.AndroidMkEntries{android.AndroidMkEntries{ Class: "APPS", OutputFile: android.OptionalPathForPath(a.outputFile), @@ -729,7 +740,7 @@ func (apkSet *AndroidAppSet) AndroidMkEntries() []android.AndroidMkEntries { ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(entries *android.AndroidMkEntries) { entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", apkSet.Privileged()) - entries.SetString("LOCAL_APK_SET_MASTER_FILE", apkSet.masterFile) + entries.SetString("LOCAL_APK_SET_INSTALL_FILE", apkSet.InstallFile()) entries.SetPath("LOCAL_APKCERTS_FILE", apkSet.apkcertsFile) entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", apkSet.properties.Overrides...) }, diff --git a/java/androidmk_test.go b/java/androidmk_test.go index 7daa6244f..075b7aa6f 100644 --- a/java/androidmk_test.go +++ b/java/androidmk_test.go @@ -156,16 +156,190 @@ func TestDistWithTag(t *testing.T) { } `) - without_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_without_tag", "android_common").Module()) - with_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_with_tag", "android_common").Module()) + withoutTagEntries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_without_tag", "android_common").Module()) + withTagEntries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_with_tag", "android_common").Module()) - if len(without_tag_entries) != 2 || len(with_tag_entries) != 2 { - t.Errorf("two mk entries per module expected, got %d and %d", len(without_tag_entries), len(with_tag_entries)) + if len(withoutTagEntries) != 2 || len(withTagEntries) != 2 { + t.Errorf("two mk entries per module expected, got %d and %d", len(withoutTagEntries), len(withTagEntries)) } - if !with_tag_entries[0].DistFile.Valid() || !strings.Contains(with_tag_entries[0].DistFile.String(), "/javac/foo_with_tag.jar") { - t.Errorf("expected classes.jar DistFile, got %v", with_tag_entries[0].DistFile) + if len(withTagEntries[0].DistFiles[".jar"]) != 1 || + !strings.Contains(withTagEntries[0].DistFiles[".jar"][0].String(), "/javac/foo_with_tag.jar") { + t.Errorf("expected DistFiles to contain classes.jar, got %v", withTagEntries[0].DistFiles) } - if without_tag_entries[0].DistFile.Valid() { - t.Errorf("did not expect explicit DistFile, got %v", without_tag_entries[0].DistFile) + if len(withoutTagEntries[0].DistFiles[".jar"]) > 0 { + t.Errorf("did not expect explicit DistFile for .jar tag, got %v", withoutTagEntries[0].DistFiles[".jar"]) + } +} + +func TestDistWithDest(t *testing.T) { + ctx, config := testJava(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + dist: { + targets: ["my_goal"], + dest: "my/custom/dest/dir", + }, + } + `) + + module := ctx.ModuleForTests("foo", "android_common").Module() + entries := android.AndroidMkEntriesForTest(t, config, "", module) + if len(entries) != 2 { + t.Errorf("Expected 2 AndroidMk entries, got %d", len(entries)) + } + + distStrings := entries[0].GetDistForGoals(module) + + if len(distStrings) != 2 { + t.Errorf("Expected 2 entries for dist: PHONY and dist-for-goals, but got %q", distStrings) + } + + if distStrings[0] != ".PHONY: my_goal\n" { + t.Errorf("Expected .PHONY entry to declare my_goal, but got: %s", distStrings[0]) + } + + if !strings.Contains(distStrings[1], "$(call dist-for-goals,my_goal") || + !strings.Contains(distStrings[1], ".intermediates/foo/android_common/dex/foo.jar:my/custom/dest/dir") { + t.Errorf( + "Expected dist-for-goals entry to contain my_goal and new dest dir, but got: %s", distStrings[1]) + } +} + +func TestDistsWithAllProperties(t *testing.T) { + ctx, config := testJava(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + dist: { + targets: ["baz"], + }, + dists: [ + { + targets: ["bar"], + tag: ".jar", + dest: "bar.jar", + dir: "bar/dir", + suffix: ".qux", + }, + ] + } + `) + + module := ctx.ModuleForTests("foo", "android_common").Module() + entries := android.AndroidMkEntriesForTest(t, config, "", module) + if len(entries) != 2 { + t.Errorf("Expected 2 AndroidMk entries, got %d", len(entries)) + } + + distStrings := entries[0].GetDistForGoals(module) + + if len(distStrings) != 4 { + t.Errorf("Expected 4 entries for dist: PHONY and dist-for-goals, but got %d", len(distStrings)) + } + + if distStrings[0] != ".PHONY: bar\n" { + t.Errorf("Expected .PHONY entry to declare bar, but got: %s", distStrings[0]) + } + + if !strings.Contains(distStrings[1], "$(call dist-for-goals,bar") || + !strings.Contains( + distStrings[1], + ".intermediates/foo/android_common/javac/foo.jar:bar/dir/bar.qux.jar") { + t.Errorf( + "Expected dist-for-goals entry to contain bar and new dest dir, but got: %s", distStrings[1]) + } + + if distStrings[2] != ".PHONY: baz\n" { + t.Errorf("Expected .PHONY entry to declare baz, but got: %s", distStrings[2]) + } + + if !strings.Contains(distStrings[3], "$(call dist-for-goals,baz") || + !strings.Contains(distStrings[3], ".intermediates/foo/android_common/dex/foo.jar:foo.jar") { + t.Errorf( + "Expected dist-for-goals entry to contain my_other_goal and new dest dir, but got: %s", + distStrings[3]) + } +} + +func TestDistsWithTag(t *testing.T) { + ctx, config := testJava(t, ` + java_library { + name: "foo_without_tag", + srcs: ["a.java"], + compile_dex: true, + dists: [ + { + targets: ["hi"], + }, + ], + } + java_library { + name: "foo_with_tag", + srcs: ["a.java"], + compile_dex: true, + dists: [ + { + targets: ["hi"], + tag: ".jar", + }, + ], + } + `) + + moduleWithoutTag := ctx.ModuleForTests("foo_without_tag", "android_common").Module() + moduleWithTag := ctx.ModuleForTests("foo_with_tag", "android_common").Module() + + withoutTagEntries := android.AndroidMkEntriesForTest(t, config, "", moduleWithoutTag) + withTagEntries := android.AndroidMkEntriesForTest(t, config, "", moduleWithTag) + + if len(withoutTagEntries) != 2 || len(withTagEntries) != 2 { + t.Errorf("two mk entries per module expected, got %d and %d", len(withoutTagEntries), len(withTagEntries)) + } + + distFilesWithoutTag := withoutTagEntries[0].DistFiles + distFilesWithTag := withTagEntries[0].DistFiles + + if len(distFilesWithTag[".jar"]) != 1 || + !strings.Contains(distFilesWithTag[".jar"][0].String(), "/javac/foo_with_tag.jar") { + t.Errorf("expected foo_with_tag's .jar-tagged DistFiles to contain classes.jar, got %v", distFilesWithTag[".jar"]) + } + if len(distFilesWithoutTag[".jar"]) > 0 { + t.Errorf("did not expect foo_without_tag's .jar-tagged DistFiles to contain files, but got %v", distFilesWithoutTag[".jar"]) + } +} + +func TestJavaSdkLibrary_RequireXmlPermissionFile(t *testing.T) { + ctx, config := testJava(t, ` + java_sdk_library { + name: "foo-shared_library", + srcs: ["a.java"], + } + java_sdk_library { + name: "foo-no_shared_library", + srcs: ["a.java"], + shared_library: false, + } + `) + + // Verify the existence of internal modules + ctx.ModuleForTests("foo-shared_library.xml", "android_common") + + testCases := []struct { + moduleName string + expected []string + }{ + {"foo-shared_library", []string{"foo-shared_library.xml"}}, + {"foo-no_shared_library", nil}, + } + for _, tc := range testCases { + mod := ctx.ModuleForTests(tc.moduleName, "android_common").Module() + entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0] + actual := entries.EntryMap["LOCAL_REQUIRED_MODULES"] + if !reflect.DeepEqual(tc.expected, actual) { + t.Errorf("Unexpected required modules - expected: %q, actual: %q", tc.expected, actual) + } } } diff --git a/java/app.go b/java/app.go index e75d8749f..900f6a6d7 100755 --- a/java/app.go +++ b/java/app.go @@ -28,6 +28,7 @@ import ( "android/soong/android" "android/soong/cc" + "android/soong/dexpreopt" "android/soong/tradefed" ) @@ -77,7 +78,7 @@ type AndroidAppSet struct { properties AndroidAppSetProperties packedOutput android.WritablePath - masterFile string + installFile string apkcertsFile android.ModuleOutPath } @@ -101,8 +102,8 @@ func (as *AndroidAppSet) OutputFile() android.Path { return as.packedOutput } -func (as *AndroidAppSet) MasterFile() string { - return as.masterFile +func (as *AndroidAppSet) InstallFile() string { + return as.installFile } func (as *AndroidAppSet) APKCertsFile() android.Path { @@ -135,10 +136,10 @@ func SupportedAbis(ctx android.ModuleContext) []string { func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { as.packedOutput = android.PathForModuleOut(ctx, ctx.ModuleName()+".zip") as.apkcertsFile = android.PathForModuleOut(ctx, "apkcerts.txt") - // We are assuming here that the master file in the APK + // We are assuming here that the install file in the APK // set has `.apk` suffix. If it doesn't the build will fail. // APK sets containing APEX files are handled elsewhere. - as.masterFile = as.BaseModuleName() + ".apk" + as.installFile = as.BaseModuleName() + ".apk" screenDensities := "all" if dpis := ctx.Config().ProductAAPTPrebuiltDPI(); len(dpis) > 0 { screenDensities = strings.ToUpper(strings.Join(dpis, ",")) @@ -166,7 +167,7 @@ func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) // android_app_set extracts a set of APKs based on the target device // configuration and installs this set as "split APKs". -// The extracted set always contains 'master' APK whose name is +// The extracted set always contains an APK whose name is // _module_name_.apk and every split APK matching target device. // The extraction of the density-specific splits depends on // PRODUCT_AAPT_PREBUILT_DPI variable. If present (its value should @@ -267,6 +268,9 @@ type overridableAppProperties struct { // the logging parent of this app. Logging_parent *string + + // Whether to rename the package in resources to the override name rather than the base name. Defaults to true. + Rename_resources_package *bool } // runtime_resource_overlay properties that can be overridden by override_runtime_resource_overlay @@ -431,8 +435,10 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { 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) + android.CheckMinSdkVersion(a, ctx, int(minSdkVersion)) } else { ctx.PropertyErrorf("min_sdk_version", "%s", err.Error()) } @@ -504,10 +510,23 @@ func (a *AndroidApp) shouldEmbedJnis(ctx android.BaseModuleContext) bool { !a.IsForPlatform() || a.appProperties.AlwaysPackageNativeLibs } +func generateAaptRenamePackageFlags(packageName string, renameResourcesPackage bool) []string { + aaptFlags := []string{"--rename-manifest-package " + packageName} + if renameResourcesPackage { + // Required to rename the package name in the resources table. + aaptFlags = append(aaptFlags, "--rename-resources-package "+packageName) + } + return aaptFlags +} + func (a *AndroidApp) OverriddenManifestPackageName() string { return a.overriddenManifestPackageName } +func (a *AndroidApp) renameResourcesPackage() bool { + return proptools.BoolDefault(a.overridableAppProperties.Rename_resources_package, true) +} + func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { a.aapt.usesNonSdkApis = Bool(a.Module.deviceProperties.Platform_apis) @@ -540,7 +559,7 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { if !overridden { manifestPackageName = *a.overridableAppProperties.Package_name } - aaptLinkFlags = append(aaptLinkFlags, "--rename-manifest-package "+manifestPackageName) + aaptLinkFlags = append(aaptLinkFlags, generateAaptRenamePackageFlags(manifestPackageName, a.renameResourcesPackage())...) a.overriddenManifestPackageName = manifestPackageName } @@ -583,18 +602,20 @@ func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath return android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk") } -func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { +func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext, sdkLibs dexpreopt.LibraryPaths) android.Path { a.dexpreopter.installPath = a.installPath(ctx) - if a.deviceProperties.Uncompress_dex == nil { + if a.dexProperties.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.dexProperties.Uncompress_dex = proptools.BoolPtr(a.shouldUncompressDex(ctx)) } - a.dexpreopter.uncompressedDex = *a.deviceProperties.Uncompress_dex + a.dexpreopter.uncompressedDex = *a.dexProperties.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.libraryPaths.AddLibraryPaths(sdkLibs) a.dexpreopter.manifestFile = a.mergedManifestFile + a.exportedSdkLibs = make(dexpreopt.LibraryPaths) if ctx.ModuleName() != "framework-res" { a.Module.compile(ctx, a.aaptSrcJar) @@ -663,16 +684,20 @@ func (a *AndroidApp) noticeBuildActions(ctx android.ModuleContext) { return false } - path := child.(android.Module).NoticeFile() - if path.Valid() { - noticePathSet[path.Path()] = true + paths := child.(android.Module).NoticeFiles() + if len(paths) > 0 { + for _, path := range paths { + noticePathSet[path] = true + } } return true }) // If the app has one, add it too. - if a.NoticeFile().Valid() { - noticePathSet[a.NoticeFile().Path()] = true + if len(a.NoticeFiles()) > 0 { + for _, path := range a.NoticeFiles() { + noticePathSet[path] = true + } } if len(noticePathSet) == 0 { @@ -759,6 +784,15 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { // Process all building blocks, from AAPT to certificates. a.aaptBuildActions(ctx) + // The decision to enforce <uses-library> checks is made before adding implicit SDK libraries. + a.usesLibrary.freezeEnforceUsesLibraries() + + // Add implicit SDK libraries to <uses-library> list. + for _, usesLib := range android.SortedStringKeys(a.aapt.sdkLibraries) { + a.usesLibrary.addLib(usesLib, inList(usesLib, optionalUsesLibs)) + } + + // Check that the <uses-library> list is coherent with the manifest. if a.usesLibrary.enforceUsesLibraries() { manifestCheckFile := a.usesLibrary.verifyUsesLibrariesManifest(ctx, a.mergedManifestFile) apkDeps = append(apkDeps, manifestCheckFile) @@ -769,9 +803,9 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.linter.mergedManifest = a.aapt.mergedManifestFile a.linter.manifest = a.aapt.manifestPath a.linter.resources = a.aapt.resourceFiles - a.linter.buildModuleReportZip = ctx.Config().UnbundledBuild() + a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps() - dexJarFile := a.dexBuildActions(ctx) + dexJarFile := a.dexBuildActions(ctx, a.aapt.sdkLibraries) jniLibs, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis)) jniJarFile := a.jniBuildActions(jniLibs, ctx) @@ -852,7 +886,7 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) - if IsJniDepTag(tag) || tag == cc.SharedDepTag { + if IsJniDepTag(tag) || cc.IsSharedDepTag(tag) { if dep, ok := module.(*cc.Module); ok { if dep.IsNdk() || dep.IsStubs() { return false @@ -902,13 +936,13 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, return jniLibs, certificates } -func (a *AndroidApp) walkPayloadDeps(ctx android.ModuleContext, - do func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool)) { - +func (a *AndroidApp) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) { ctx.WalkDeps(func(child, parent android.Module) bool { isExternal := !a.DepIsInSameApex(ctx, child) if am, ok := child.(android.ApexModule); ok { - do(ctx, parent, am, isExternal) + if !do(ctx, parent, am, isExternal) { + return false + } } return !isExternal }) @@ -920,7 +954,7 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { } depsInfo := android.DepNameToDepInfoMap{} - a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) { + a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { depName := to.Name() if info, exist := depsInfo[depName]; exist { info.From = append(info.From, from.Name()) @@ -940,6 +974,7 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { MinSdkVersion: toMinSdkVersion, } } + return true }) a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(), depsInfo) @@ -969,6 +1004,8 @@ func (a *AndroidApp) OutputFiles(tag string) (android.Paths, error) { switch tag { case ".aapt.srcjar": return []android.Path{a.aaptSrcJar}, nil + case ".export-package.apk": + return []android.Path{a.exportPackage}, nil } return a.Library.OutputFiles(tag) } @@ -993,14 +1030,16 @@ func (a *AndroidApp) MarkAsCoverageVariant(coverage bool) { a.appProperties.IsCoverageVariant = coverage } +func (a *AndroidApp) EnableCoverageIfNeeded() {} + var _ cc.Coverage = (*AndroidApp)(nil) // android_app compiles sources and Android resources into an Android application package `.apk` file. func AndroidAppFactory() android.Module { module := &AndroidApp{} - module.Module.deviceProperties.Optimize.EnabledByDefault = true - module.Module.deviceProperties.Optimize.Shrink = proptools.BoolPtr(true) + module.Module.dexProperties.Optimize.EnabledByDefault = true + module.Module.dexProperties.Optimize.Shrink = proptools.BoolPtr(true) module.Module.properties.Instrument = true module.Module.properties.Installable = proptools.BoolPtr(true) @@ -1012,10 +1051,6 @@ func AndroidAppFactory() android.Module { &module.overridableAppProperties, &module.usesLibrary.usesLibraryProperties) - module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool { - return class == android.Device && ctx.Config().DevicePrefer32BitApps() - }) - android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) android.InitOverridableModule(module, &module.appProperties.Overrides) @@ -1025,6 +1060,7 @@ func AndroidAppFactory() android.Module { } type appTestProperties struct { + // The name of the android_app module that the tests will run against. Instrumentation_for *string // if specified, the instrumentation target package name in the manifest is overwritten by it. @@ -1038,8 +1074,9 @@ type AndroidTest struct { testProperties testProperties - testConfig android.Path - data android.Paths + testConfig android.Path + extraTestConfigs android.Paths + data android.Paths } func (a *AndroidTest) InstallInTestcases() bool { @@ -1067,6 +1104,7 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { testConfig := tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_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.extraTestConfigs = android.PathsForModuleSrc(ctx, a.testProperties.Test_options.Extra_test_configs) a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data) } @@ -1117,7 +1155,7 @@ func (a *AndroidTest) OverridablePropertiesDepsMutator(ctx android.BottomUpMutat func AndroidTestFactory() android.Module { module := &AndroidTest{} - module.Module.deviceProperties.Optimize.EnabledByDefault = true + module.Module.dexProperties.Optimize.EnabledByDefault = true module.Module.properties.Instrument = true module.Module.properties.Installable = proptools.BoolPtr(true) @@ -1168,7 +1206,7 @@ func (a *AndroidTestHelperApp) InstallInTestcases() bool { func AndroidTestHelperAppFactory() android.Module { module := &AndroidTestHelperApp{} - module.Module.deviceProperties.Optimize.EnabledByDefault = true + module.Module.dexProperties.Optimize.EnabledByDefault = true module.Module.properties.Installable = proptools.BoolPtr(true) module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true) @@ -1285,6 +1323,7 @@ func OverrideRuntimeResourceOverlayModuleFactory() android.Module { type AndroidAppImport struct { android.ModuleBase android.DefaultableModuleBase + android.ApexModuleBase prebuilt android.Prebuilt properties AndroidAppImportProperties @@ -1535,7 +1574,9 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext // TODO: Optionally compress the output apk. - a.installPath = ctx.InstallFile(installDir, apkFilename, a.outputFile) + if a.IsForPlatform() { + a.installPath = ctx.InstallFile(installDir, apkFilename, a.outputFile) + } // TODO: androidmk converter jni libs } @@ -1586,6 +1627,13 @@ func (a *AndroidAppImport) Privileged() bool { return Bool(a.properties.Privileged) } +func (a *AndroidAppImport) DepIsInSameApex(_ android.BaseModuleContext, _ android.Module) bool { + // android_app_import might have extra dependencies via uses_libs property. + // Don't track the dependency as we don't automatically add those libraries + // to the classpath. It should be explicitly added to java_libs property of APEX + return false +} + func (a *AndroidAppImport) sdkVersion() sdkSpec { return sdkSpecFrom("") } @@ -1594,6 +1642,11 @@ func (a *AndroidAppImport) minSdkVersion() sdkSpec { return sdkSpecFrom("") } +func (j *AndroidAppImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + // Do not check for prebuilts against the min_sdk_version of enclosing APEX + return nil +} + func createVariantGroupType(variants []string, variantGroupName string) reflect.Type { props := reflect.TypeOf((*AndroidAppImportProperties)(nil)) @@ -1640,6 +1693,7 @@ func AndroidAppImportFactory() android.Module { module.processVariants(ctx) }) + android.InitApexModule(module) android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk") @@ -1690,6 +1744,7 @@ func AndroidTestImportFactory() android.Module { module.dexpreopter.isTest = true + android.InitApexModule(module) android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk") @@ -1746,6 +1801,15 @@ type RuntimeResourceOverlayProperties struct { Overrides []string } +// RuntimeResourceOverlayModule interface is used by the apex package to gather information from +// a RuntimeResourceOverlay module. +type RuntimeResourceOverlayModule interface { + android.Module + OutputFile() android.Path + Certificate() Certificate + Theme() string +} + func (r *RuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) { sdkDep := decodeSdkDep(ctx, sdkContext(r)) if sdkDep.hasFrameworkLibs() { @@ -1773,7 +1837,7 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC if !overridden { manifestPackageName = *r.overridableProperties.Package_name } - aaptLinkFlags = append(aaptLinkFlags, "--rename-manifest-package "+manifestPackageName) + aaptLinkFlags = append(aaptLinkFlags, generateAaptRenamePackageFlags(manifestPackageName, false)...) } if r.overridableProperties.Target_package_name != nil { aaptLinkFlags = append(aaptLinkFlags, @@ -1816,6 +1880,18 @@ func (r *RuntimeResourceOverlay) targetSdkVersion() sdkSpec { return r.sdkVersion() } +func (r *RuntimeResourceOverlay) Certificate() Certificate { + return r.certificate +} + +func (r *RuntimeResourceOverlay) OutputFile() android.Path { + return r.outputFile +} + +func (r *RuntimeResourceOverlay) Theme() string { + return String(r.properties.Theme) +} + // runtime_resource_overlay generates a resource-only apk file that can overlay application and // system resources at run time. func RuntimeResourceOverlayFactory() android.Module { @@ -1852,6 +1928,16 @@ type usesLibrary struct { usesLibraryProperties UsesLibraryProperties } +func (u *usesLibrary) addLib(lib string, optional bool) { + if !android.InList(lib, u.usesLibraryProperties.Uses_libs) && !android.InList(lib, u.usesLibraryProperties.Optional_uses_libs) { + if optional { + u.usesLibraryProperties.Optional_uses_libs = append(u.usesLibraryProperties.Optional_uses_libs, lib) + } else { + u.usesLibraryProperties.Uses_libs = append(u.usesLibraryProperties.Uses_libs, lib) + } + } +} + func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, hasFrameworkLibs bool) { if !ctx.Config().UnbundledBuild() { ctx.AddVariationDependencies(nil, usesLibTag, u.usesLibraryProperties.Uses_libs...) @@ -1860,13 +1946,13 @@ func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, hasFrameworkLibs // creating a cyclic dependency: // e.g. framework-res -> org.apache.http.legacy -> ... -> framework-res. if hasFrameworkLibs { - // dexpreopt/dexpreopt.go needs the paths to the dex jars of these libraries in case construct_context.sh needs - // to pass them to dex2oat. Add them as a dependency so we can determine the path to the dex jar of each - // library to dexpreopt. + // Dexpreopt needs paths to the dex jars of these libraries in order to construct + // class loader context for dex2oat. Add them as a dependency with a special tag. ctx.AddVariationDependencies(nil, usesLibTag, "org.apache.http.legacy", "android.hidl.base-V1.0-java", "android.hidl.manager-V1.0-java") + ctx.AddVariationDependencies(nil, usesLibTag, optionalUsesLibs...) } } } @@ -1878,24 +1964,36 @@ func (u *usesLibrary) presentOptionalUsesLibs(ctx android.BaseModuleContext) []s return optionalUsesLibs } -// usesLibraryPaths returns a map of module names of shared library dependencies to the paths to their dex jars. -func (u *usesLibrary) usesLibraryPaths(ctx android.ModuleContext) map[string]android.Path { - usesLibPaths := make(map[string]android.Path) +// usesLibraryPaths returns a map of module names of shared library dependencies to the paths +// to their dex jars on host and on device. +func (u *usesLibrary) usesLibraryPaths(ctx android.ModuleContext) dexpreopt.LibraryPaths { + usesLibPaths := make(dexpreopt.LibraryPaths) if !ctx.Config().UnbundledBuild() { ctx.VisitDirectDepsWithTag(usesLibTag, func(m android.Module) { + dep := ctx.OtherModuleName(m) if lib, ok := m.(Dependency); ok { - if dexJar := lib.DexJar(); dexJar != nil { - usesLibPaths[ctx.OtherModuleName(m)] = dexJar + buildPath := lib.DexJarBuildPath() + if buildPath == nil { + ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must"+ + " produce a dex jar, does it have installable: true?", dep) + return + } + + var devicePath string + installPath := lib.DexJarInstallPath() + if installPath == nil { + devicePath = filepath.Join("/system/framework", dep+".jar") } else { - ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must produce a dex jar, does it have installable: true?", - ctx.OtherModuleName(m)) + devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath)) } + + usesLibPaths[dep] = &dexpreopt.LibraryPath{buildPath, devicePath} } else if ctx.Config().AllowMissingDependencies() { - ctx.AddMissingDependencies([]string{ctx.OtherModuleName(m)}) + ctx.AddMissingDependencies([]string{dep}) } else { - ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be a java library", - ctx.OtherModuleName(m)) + ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be "+ + "a java library", dep) } }) } @@ -1912,6 +2010,12 @@ func (u *usesLibrary) enforceUsesLibraries() bool { return BoolDefault(u.usesLibraryProperties.Enforce_uses_libs, defaultEnforceUsesLibs) } +// Freeze the value of `enforce_uses_libs` based on the current values of `uses_libs` and `optional_uses_libs`. +func (u *usesLibrary) freezeEnforceUsesLibraries() { + enforce := u.enforceUsesLibraries() + u.usesLibraryProperties.Enforce_uses_libs = &enforce +} + // verifyUsesLibrariesManifest checks the <uses-library> tags in an AndroidManifest.xml against the ones specified // in the uses_libs and optional_uses_libs properties. It returns the path to a copy of the manifest. func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path) android.Path { diff --git a/java/app_test.go b/java/app_test.go index 8ef315206..536797119 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -161,11 +161,11 @@ func TestAndroidAppSet(t *testing.T) { t.Errorf("wrong partition value: '%s', expected 'system'", 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) + actualInstallFile := mkEntries.EntryMap["LOCAL_APK_SET_INSTALL_FILE"] + expectedInstallFile := []string{"foo.apk"} + if !reflect.DeepEqual(actualInstallFile, expectedInstallFile) { + t.Errorf("Unexpected LOCAL_APK_SET_INSTALL_FILE value: '%s', expected: '%s',", + actualInstallFile, expectedInstallFile) } } @@ -478,6 +478,24 @@ func TestUpdatableApps(t *testing.T) { } } +func TestUpdatableApps_TransitiveDepsShouldSetMinSdkVersion(t *testing.T) { + testJavaError(t, `module "bar".*: should support min_sdk_version\(29\)`, cc.GatherRequiredDepsForTest(android.Android)+` + android_app { + name: "foo", + srcs: ["a.java"], + updatable: true, + sdk_version: "current", + min_sdk_version: "29", + static_libs: ["bar"], + } + + java_library { + name: "bar", + sdk_version: "current", + } + `) +} + func TestUpdatableApps_JniLibsShouldShouldSupportMinSdkVersion(t *testing.T) { testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` android_app { @@ -515,16 +533,6 @@ func TestUpdatableApps_JniLibShouldBeBuiltAgainstMinSdkVersion(t *testing.T) { 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, @@ -537,16 +545,28 @@ func TestUpdatableApps_JniLibShouldBeBuiltAgainstMinSdkVersion(t *testing.T) { inputs := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared").Description("link").Implicits var crtbeginFound, crtendFound bool + expectedCrtBegin := ctx.ModuleForTests("crtbegin_so", + "android_arm64_armv8-a_sdk_29").Rule("partialLd").Output + expectedCrtEnd := ctx.ModuleForTests("crtend_so", + "android_arm64_armv8-a_sdk_29").Rule("partialLd").Output + implicits := []string{} for _, input := range inputs { - switch input.String() { - case "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtbegin_so.o": + implicits = append(implicits, input.String()) + if strings.HasSuffix(input.String(), expectedCrtBegin.String()) { crtbeginFound = true - case "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtend_so.o": + } else if strings.HasSuffix(input.String(), expectedCrtEnd.String()) { crtendFound = true } } - if !crtbeginFound || !crtendFound { - t.Error("should link with ndk_crtbegin_so.29 and ndk_crtend_so.29") + if !crtbeginFound { + t.Error(fmt.Sprintf( + "expected implicit with suffix %q, have the following implicits:\n%s", + expectedCrtBegin, strings.Join(implicits, "\n"))) + } + if !crtendFound { + t.Error(fmt.Sprintf( + "expected implicit with suffix %q, have the following implicits:\n%s", + expectedCrtEnd, strings.Join(implicits, "\n"))) } } @@ -1020,6 +1040,35 @@ func TestAndroidResources(t *testing.T) { } } +func checkSdkVersion(t *testing.T, config android.Config, expectedSdkVersion string) { + ctx := testContext() + + run(t, ctx, config) + + foo := ctx.ModuleForTests("foo", "android_common") + link := foo.Output("package-res.apk") + linkFlags := strings.Split(link.Args["flags"], " ") + min := android.IndexList("--min-sdk-version", linkFlags) + target := android.IndexList("--target-sdk-version", linkFlags) + + if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 { + t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags) + } + + gotMinSdkVersion := linkFlags[min+1] + gotTargetSdkVersion := linkFlags[target+1] + + if gotMinSdkVersion != expectedSdkVersion { + t.Errorf("incorrect --min-sdk-version, expected %q got %q", + expectedSdkVersion, gotMinSdkVersion) + } + + if gotTargetSdkVersion != expectedSdkVersion { + t.Errorf("incorrect --target-sdk-version, expected %q got %q", + expectedSdkVersion, gotTargetSdkVersion) + } +} + func TestAppSdkVersion(t *testing.T) { testCases := []struct { name string @@ -1089,34 +1138,81 @@ func TestAppSdkVersion(t *testing.T) { config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal + checkSdkVersion(t, config, test.expectedMinSdkVersion) - ctx := testContext() - - run(t, ctx, config) - - foo := ctx.ModuleForTests("foo", "android_common") - link := foo.Output("package-res.apk") - linkFlags := strings.Split(link.Args["flags"], " ") - min := android.IndexList("--min-sdk-version", linkFlags) - target := android.IndexList("--target-sdk-version", linkFlags) - - if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 { - t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags) - } - - gotMinSdkVersion := linkFlags[min+1] - gotTargetSdkVersion := linkFlags[target+1] + }) + } + } +} - if gotMinSdkVersion != test.expectedMinSdkVersion { - t.Errorf("incorrect --min-sdk-version, expected %q got %q", - test.expectedMinSdkVersion, gotMinSdkVersion) - } +func TestVendorAppSdkVersion(t *testing.T) { + testCases := []struct { + name string + sdkVersion string + platformSdkInt int + platformSdkCodename string + platformSdkFinal bool + deviceCurrentApiLevelForVendorModules string + expectedMinSdkVersion string + }{ + { + name: "current final SDK", + sdkVersion: "current", + platformSdkInt: 29, + platformSdkCodename: "REL", + platformSdkFinal: true, + deviceCurrentApiLevelForVendorModules: "29", + expectedMinSdkVersion: "29", + }, + { + name: "current final SDK", + sdkVersion: "current", + platformSdkInt: 29, + platformSdkCodename: "REL", + platformSdkFinal: true, + deviceCurrentApiLevelForVendorModules: "28", + expectedMinSdkVersion: "28", + }, + { + name: "current final SDK", + sdkVersion: "current", + platformSdkInt: 29, + platformSdkCodename: "Q", + platformSdkFinal: false, + deviceCurrentApiLevelForVendorModules: "current", + expectedMinSdkVersion: "Q", + }, + { + name: "current final SDK", + sdkVersion: "current", + platformSdkInt: 29, + platformSdkCodename: "Q", + platformSdkFinal: false, + deviceCurrentApiLevelForVendorModules: "28", + expectedMinSdkVersion: "28", + }, + } - if gotTargetSdkVersion != test.expectedMinSdkVersion { - t.Errorf("incorrect --target-sdk-version, expected %q got %q", - test.expectedMinSdkVersion, gotTargetSdkVersion) - } - }) + for _, moduleType := range []string{"android_app", "android_library"} { + for _, sdkKind := range []string{"", "system_"} { + for _, test := range testCases { + t.Run(moduleType+" "+test.name, func(t *testing.T) { + bp := fmt.Sprintf(`%s { + name: "foo", + srcs: ["a.java"], + sdk_version: "%s%s", + vendor: true, + }`, moduleType, sdkKind, test.sdkVersion) + + config := testAppConfig(nil, bp, nil) + config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt + config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename + config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal + config.TestProductVariables.DeviceCurrentApiLevelForVendorModules = &test.deviceCurrentApiLevelForVendorModules + config.TestProductVariables.DeviceSystemSdkVersions = []string{"28", "29"} + checkSdkVersion(t, config, test.expectedMinSdkVersion) + }) + } } } } @@ -1743,52 +1839,125 @@ func TestOverrideAndroidApp(t *testing.T) { base: "foo", package_name: "org.dandroid.bp", } + + override_android_app { + name: "baz_no_rename_resources", + base: "foo", + package_name: "org.dandroid.bp", + rename_resources_package: false, + } + + android_app { + name: "foo_no_rename_resources", + srcs: ["a.java"], + certificate: "expiredkey", + overrides: ["qux"], + rename_resources_package: false, + sdk_version: "current", + } + + override_android_app { + name: "baz_base_no_rename_resources", + base: "foo_no_rename_resources", + package_name: "org.dandroid.bp", + } + + override_android_app { + name: "baz_override_base_rename_resources", + base: "foo_no_rename_resources", + package_name: "org.dandroid.bp", + rename_resources_package: true, + } `) expectedVariants := []struct { - moduleName string - variantName string - apkName string - apkPath string - certFlag string - lineageFlag string - overrides []string - aaptFlag string - logging_parent string + name string + moduleName string + variantName string + apkName string + apkPath string + certFlag string + lineageFlag string + overrides []string + packageFlag string + renameResources bool + logging_parent string }{ { - moduleName: "foo", - variantName: "android_common", - apkPath: "/target/product/test_device/system/app/foo/foo.apk", - certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", - lineageFlag: "", - overrides: []string{"qux"}, - aaptFlag: "", - logging_parent: "", - }, - { - moduleName: "bar", - variantName: "android_common_bar", - apkPath: "/target/product/test_device/system/app/bar/bar.apk", - certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8", - lineageFlag: "--lineage lineage.bin", - overrides: []string{"qux", "foo"}, - aaptFlag: "", - logging_parent: "bah", - }, - { - moduleName: "baz", - variantName: "android_common_baz", - apkPath: "/target/product/test_device/system/app/baz/baz.apk", - certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", - lineageFlag: "", - overrides: []string{"qux", "foo"}, - aaptFlag: "--rename-manifest-package org.dandroid.bp", - logging_parent: "", + name: "foo", + moduleName: "foo", + variantName: "android_common", + apkPath: "/target/product/test_device/system/app/foo/foo.apk", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", + overrides: []string{"qux"}, + packageFlag: "", + renameResources: false, + logging_parent: "", + }, + { + name: "foo", + moduleName: "bar", + variantName: "android_common_bar", + apkPath: "/target/product/test_device/system/app/bar/bar.apk", + certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8", + lineageFlag: "--lineage lineage.bin", + overrides: []string{"qux", "foo"}, + packageFlag: "", + renameResources: false, + logging_parent: "bah", + }, + { + name: "foo", + moduleName: "baz", + variantName: "android_common_baz", + apkPath: "/target/product/test_device/system/app/baz/baz.apk", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", + overrides: []string{"qux", "foo"}, + packageFlag: "org.dandroid.bp", + renameResources: true, + logging_parent: "", + }, + { + name: "foo", + moduleName: "baz_no_rename_resources", + variantName: "android_common_baz_no_rename_resources", + apkPath: "/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", + overrides: []string{"qux", "foo"}, + packageFlag: "org.dandroid.bp", + renameResources: false, + logging_parent: "", + }, + { + name: "foo_no_rename_resources", + moduleName: "baz_base_no_rename_resources", + variantName: "android_common_baz_base_no_rename_resources", + apkPath: "/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", + overrides: []string{"qux", "foo_no_rename_resources"}, + packageFlag: "org.dandroid.bp", + renameResources: false, + logging_parent: "", + }, + { + name: "foo_no_rename_resources", + moduleName: "baz_override_base_rename_resources", + variantName: "android_common_baz_override_base_rename_resources", + apkPath: "/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", + overrides: []string{"qux", "foo_no_rename_resources"}, + packageFlag: "org.dandroid.bp", + renameResources: true, + logging_parent: "", }, } for _, expected := range expectedVariants { - variant := ctx.ModuleForTests("foo", expected.variantName) + variant := ctx.ModuleForTests(expected.name, expected.variantName) // Check the final apk name outputs := variant.AllOutputs() @@ -1834,9 +2003,12 @@ func TestOverrideAndroidApp(t *testing.T) { // Check the package renaming flag, if exists. res := variant.Output("package-res.apk") aapt2Flags := res.Args["flags"] - if !strings.Contains(aapt2Flags, expected.aaptFlag) { - t.Errorf("package renaming flag, %q is missing in aapt2 link flags, %q", expected.aaptFlag, aapt2Flags) + checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag) + expectedPackage := expected.packageFlag + if !expected.renameResources { + expectedPackage = "" } + checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", expectedPackage) } } @@ -1973,6 +2145,7 @@ func TestOverrideAndroidTest(t *testing.T) { res := variant.Output("package-res.apk") aapt2Flags := res.Args["flags"] checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag) + checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", expected.packageFlag) checkAapt2LinkFlag(t, aapt2Flags, "rename-instrumentation-target-package", expected.targetPackageFlag) } } @@ -2568,10 +2741,37 @@ func TestUsesLibraries(t *testing.T) { sdk_version: "current", } + java_sdk_library { + name: "runtime-library", + srcs: ["a.java"], + sdk_version: "current", + } + + java_library { + name: "static-runtime-helper", + srcs: ["a.java"], + libs: ["runtime-library"], + sdk_version: "current", + } + android_app { name: "app", srcs: ["a.java"], + libs: ["qux", "quuz"], + static_libs: ["static-runtime-helper"], + uses_libs: ["foo"], + sdk_version: "current", + optional_uses_libs: [ + "bar", + "baz", + ], + } + + android_app { + name: "app_with_stub_deps", + srcs: ["a.java"], libs: ["qux", "quuz.stubs"], + static_libs: ["static-runtime-helper"], uses_libs: ["foo"], sdk_version: "current", optional_uses_libs: [ @@ -2600,15 +2800,15 @@ func TestUsesLibraries(t *testing.T) { run(t, ctx, config) app := ctx.ModuleForTests("app", "android_common") + appWithStubDeps := ctx.ModuleForTests("app_with_stub_deps", "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) + for _, w := range []string{"qux", "quuz", "runtime-library"} { + if !strings.Contains(manifestFixerArgs, "--uses-library "+w) { + t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs) + } } // Test that all libraries are verified @@ -2631,16 +2831,25 @@ func TestUsesLibraries(t *testing.T) { t.Errorf("wanted %q in %q", w, cmd) } - // Test that only present libraries are preopted + // Test that all present libraries are preopted, including implicit SDK dependencies cmd = app.Rule("dexpreopt").RuleParams.Command - - if w := `dex_preopt_target_libraries="/system/framework/foo.jar /system/framework/bar.jar"`; !strings.Contains(cmd, w) { + w := `--target-classpath-for-sdk any` + + ` /system/framework/foo.jar` + + `:/system/framework/quuz.jar` + + `:/system/framework/qux.jar` + + `:/system/framework/runtime-library.jar` + + `:/system/framework/bar.jar` + if !strings.Contains(cmd, w) { t.Errorf("wanted %q in %q", w, cmd) } - cmd = prebuilt.Rule("dexpreopt").RuleParams.Command + // TODO(skvadrik) fix dexpreopt for stub libraries for which the implementation is present + if appWithStubDeps.MaybeRule("dexpreopt").RuleParams.Command != "" { + t.Errorf("dexpreopt should be disabled for apps with dependencies on stub libraries") + } - if w := `dex_preopt_target_libraries="/system/framework/foo.jar /system/framework/bar.jar"`; !strings.Contains(cmd, w) { + cmd = prebuilt.Rule("dexpreopt").RuleParams.Command + if w := `--target-classpath-for-sdk any /system/framework/foo.jar:/system/framework/bar.jar`; !strings.Contains(cmd, w) { t.Errorf("wanted %q in %q", w, cmd) } } @@ -2910,6 +3119,7 @@ func TestUncompressDex(t *testing.T) { config := testAppConfig(nil, bp, nil) if unbundled { config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true) + config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(true) } ctx := testContext() @@ -3190,6 +3400,7 @@ func TestOverrideRuntimeResourceOverlay(t *testing.T) { res := variant.Output("package-res.apk") aapt2Flags := res.Args["flags"] checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag) + checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", "") checkAapt2LinkFlag(t, aapt2Flags, "rename-overlay-target-package", expected.targetPackageFlag) } } diff --git a/java/config/config.go b/java/config/config.go index 95add017d..31e2b0ffe 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -28,11 +28,13 @@ import ( var ( pctx = android.NewPackageContext("android/soong/java/config") - DefaultBootclasspathLibraries = []string{"core.platform.api.stubs", "core-lambda-stubs"} - DefaultSystemModules = "core-platform-api-stubs-system-modules" - DefaultLibraries = []string{"ext", "framework"} - DefaultLambdaStubsLibrary = "core-lambda-stubs" - SdkLambdaStubsPath = "prebuilts/sdk/tools/core-lambda-stubs.jar" + LegacyCorePlatformBootclasspathLibraries = []string{"legacy.core.platform.api.stubs", "core-lambda-stubs"} + LegacyCorePlatformSystemModules = "legacy-core-platform-api-stubs-system-modules" + StableCorePlatformBootclasspathLibraries = []string{"stable.core.platform.api.stubs", "core-lambda-stubs"} + StableCorePlatformSystemModules = "stable-core-platform-api-stubs-system-modules" + FrameworkLibraries = []string{"ext", "framework"} + DefaultLambdaStubsLibrary = "core-lambda-stubs" + SdkLambdaStubsPath = "prebuilts/sdk/tools/core-lambda-stubs.jar" DefaultMakeJacocoExcludeFilter = []string{"org.junit.*", "org.jacoco.*", "org.mockito.*"} DefaultJacocoExcludeFilter = []string{"org.junit.**", "org.jacoco.**", "org.mockito.**"} @@ -112,7 +114,7 @@ func init() { pctx.SourcePathVariable("JavaKytheExtractorJar", "prebuilts/build-tools/common/framework/javac_extractor.jar") pctx.SourcePathVariable("Ziptime", "prebuilts/build-tools/${hostPrebuiltTag}/bin/ziptime") - pctx.SourcePathVariable("GenKotlinBuildFileCmd", "build/soong/scripts/gen-kotlin-build-file.sh") + pctx.HostBinToolVariable("GenKotlinBuildFileCmd", "gen-kotlin-build-file.py") pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh") pctx.SourcePathVariable("PackageCheckCmd", "build/soong/scripts/package-check.sh") @@ -128,7 +130,7 @@ func init() { pctx.HostBinToolVariable("ExtractApksCmd", "extract_apks") pctx.VariableFunc("TurbineJar", func(ctx android.PackageVarContext) string { turbine := "turbine.jar" - if ctx.Config().UnbundledBuild() { + if ctx.Config().AlwaysUsePrebuiltSdks() { return "prebuilts/build-tools/common/framework/" + turbine } else { return ctx.Config().HostJavaToolPath(ctx, turbine).String() @@ -148,9 +150,9 @@ func init() { pctx.HostBinToolVariable("DexpreoptGen", "dexpreopt_gen") pctx.VariableFunc("REJavaPool", remoteexec.EnvOverrideFunc("RBE_JAVA_POOL", "java16")) - 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("REJavacExecStrategy", remoteexec.EnvOverrideFunc("RBE_JAVAC_EXEC_STRATEGY", remoteexec.RemoteLocalFallbackExecStrategy)) + pctx.VariableFunc("RED8ExecStrategy", remoteexec.EnvOverrideFunc("RBE_D8_EXEC_STRATEGY", remoteexec.RemoteLocalFallbackExecStrategy)) + pctx.VariableFunc("RER8ExecStrategy", remoteexec.EnvOverrideFunc("RBE_R8_EXEC_STRATEGY", remoteexec.RemoteLocalFallbackExecStrategy)) 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)) @@ -163,7 +165,7 @@ func init() { pctx.HostBinToolVariable("ManifestMergerCmd", "manifest-merger") - pctx.HostBinToolVariable("Class2Greylist", "class2greylist") + pctx.HostBinToolVariable("Class2NonSdkList", "class2nonsdklist") pctx.HostBinToolVariable("HiddenAPI", "hiddenapi") hostBinToolVariableWithSdkToolsPrebuilt("Aapt2Cmd", "aapt2") @@ -178,7 +180,7 @@ func init() { func hostBinToolVariableWithSdkToolsPrebuilt(name, tool string) { pctx.VariableFunc(name, func(ctx android.PackageVarContext) string { - if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() { + if ctx.Config().AlwaysUsePrebuiltSdks() { return filepath.Join("prebuilts/sdk/tools", runtime.GOOS, "bin", tool) } else { return ctx.Config().HostToolPath(ctx, tool).String() @@ -188,7 +190,7 @@ func hostBinToolVariableWithSdkToolsPrebuilt(name, tool string) { func hostJavaToolVariableWithSdkToolsPrebuilt(name, tool string) { pctx.VariableFunc(name, func(ctx android.PackageVarContext) string { - if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() { + if ctx.Config().AlwaysUsePrebuiltSdks() { return filepath.Join("prebuilts/sdk/tools/lib", tool+".jar") } else { return ctx.Config().HostJavaToolPath(ctx, tool+".jar").String() @@ -198,7 +200,7 @@ func hostJavaToolVariableWithSdkToolsPrebuilt(name, tool string) { func hostJNIToolVariableWithSdkToolsPrebuilt(name, tool string) { pctx.VariableFunc(name, func(ctx android.PackageVarContext) string { - if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() { + if ctx.Config().AlwaysUsePrebuiltSdks() { ext := ".so" if runtime.GOOS == "darwin" { ext = ".dylib" @@ -212,7 +214,7 @@ func hostJNIToolVariableWithSdkToolsPrebuilt(name, tool string) { func hostBinToolVariableWithBuildToolsPrebuilt(name, tool string) { pctx.VariableFunc(name, func(ctx android.PackageVarContext) string { - if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() { + if ctx.Config().AlwaysUsePrebuiltSdks() { return filepath.Join("prebuilts/build-tools", ctx.Config().PrebuiltOS(), "bin", tool) } else { return ctx.Config().HostToolPath(ctx, tool).String() diff --git a/java/config/makevars.go b/java/config/makevars.go index b355fad87..df447a129 100644 --- a/java/config/makevars.go +++ b/java/config/makevars.go @@ -25,9 +25,11 @@ func init() { } func makeVarsProvider(ctx android.MakeVarsContext) { - ctx.Strict("TARGET_DEFAULT_JAVA_LIBRARIES", strings.Join(DefaultLibraries, " ")) - ctx.Strict("TARGET_DEFAULT_BOOTCLASSPATH_LIBRARIES", strings.Join(DefaultBootclasspathLibraries, " ")) - ctx.Strict("DEFAULT_SYSTEM_MODULES", DefaultSystemModules) + ctx.Strict("FRAMEWORK_LIBRARIES", strings.Join(FrameworkLibraries, " ")) + + // These are used by make when LOCAL_PRIVATE_PLATFORM_APIS is set (equivalent to platform_apis in blueprint): + ctx.Strict("LEGACY_CORE_PLATFORM_BOOTCLASSPATH_LIBRARIES", strings.Join(LegacyCorePlatformBootclasspathLibraries, " ")) + ctx.Strict("LEGACY_CORE_PLATFORM_SYSTEM_MODULES", LegacyCorePlatformSystemModules) ctx.Strict("ANDROID_JAVA_HOME", "${JavaHome}") ctx.Strict("ANDROID_JAVA8_HOME", "prebuilts/jdk/jdk8/${hostPrebuiltTag}") @@ -73,7 +75,7 @@ func makeVarsProvider(ctx android.MakeVarsContext) { ctx.Strict("ANDROID_MANIFEST_MERGER", "${ManifestMergerCmd}") - ctx.Strict("CLASS2GREYLIST", "${Class2Greylist}") + ctx.Strict("CLASS2NONSDKLIST", "${Class2NonSdkList}") ctx.Strict("HIDDENAPI", "${HiddenAPI}") ctx.Strict("DEX_FLAGS", "${DexFlags}") diff --git a/java/device_host_converter.go b/java/device_host_converter.go index 11e68eb6c..40a2280d9 100644 --- a/java/device_host_converter.go +++ b/java/device_host_converter.go @@ -19,6 +19,7 @@ import ( "io" "android/soong/android" + "android/soong/dexpreopt" ) type DeviceHostConverter struct { @@ -150,7 +151,11 @@ func (d *DeviceHostConverter) ImplementationAndResourcesJars() android.Paths { return d.implementationAndResourceJars } -func (d *DeviceHostConverter) DexJar() android.Path { +func (d *DeviceHostConverter) DexJarBuildPath() android.Path { + return nil +} + +func (d *DeviceHostConverter) DexJarInstallPath() android.Path { return nil } @@ -158,7 +163,7 @@ func (d *DeviceHostConverter) AidlIncludeDirs() android.Paths { return nil } -func (d *DeviceHostConverter) ExportedSdkLibs() []string { +func (d *DeviceHostConverter) ExportedSdkLibs() dexpreopt.LibraryPaths { return nil } diff --git a/java/dex.go b/java/dex.go index 9e61e95ad..c85914c41 100644 --- a/java/dex.go +++ b/java/dex.go @@ -24,6 +24,61 @@ import ( "android/soong/remoteexec" ) +type DexProperties struct { + // If set to true, compile dex regardless of installable. Defaults to false. + Compile_dex *bool + + // list of module-specific flags that will be used for dex compiles + Dxflags []string `android:"arch_variant"` + + Optimize struct { + // If false, disable all optimization. Defaults to true for android_app and android_test + // modules, false for java_library and java_test modules. + Enabled *bool + // True if the module containing this has it set by default. + EnabledByDefault bool `blueprint:"mutated"` + + // If true, optimize for size by removing unused code. Defaults to true for apps, + // false for libraries and tests. + Shrink *bool + + // If true, optimize bytecode. Defaults to false. + Optimize *bool + + // If true, obfuscate bytecode. Defaults to false. + Obfuscate *bool + + // If true, do not use the flag files generated by aapt that automatically keep + // classes referenced by the app manifest. Defaults to false. + No_aapt_flags *bool + + // Flags to pass to proguard. + Proguard_flags []string + + // Specifies the locations of files containing proguard flags. + Proguard_flags_files []string `android:"path"` + } + + // 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 +} + +type dexer struct { + dexProperties DexProperties + + // list of extra proguard flag files + extraProguardFlagFiles android.Paths + proguardDictionary android.OptionalPath + proguardUsageZip android.OptionalPath +} + +func (d *dexer) effectiveOptimizeEnabled() bool { + return BoolDefault(d.dexProperties.Optimize.Enabled, d.dexProperties.Optimize.EnabledByDefault) +} + var d8, d8RE = remoteexec.MultiCommandStaticRules(pctx, "d8", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + @@ -55,13 +110,17 @@ var d8, d8RE = remoteexec.MultiCommandStaticRules(pctx, "d8", var r8, r8RE = remoteexec.MultiCommandStaticRules(pctx, "r8", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + - `rm -f "$outDict" && ` + + `rm -f "$outDict" && rm -rf "${outUsageDir}" && ` + + `mkdir -p $$(dirname ${outUsage}) && ` + `$r8Template${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` + `--force-proguard-compatibility ` + `--no-data-resources ` + - `-printmapping $outDict ` + + `-printmapping ${outDict} ` + + `-printusage ${outUsage} ` + `$r8Flags && ` + - `touch "$outDict" && ` + + `touch "${outDict}" "${outUsage}" && ` + + `${config.SoongZipCmd} -o ${outUsageZip} -C ${outUsageDir} -f ${outUsage} && ` + + `rm -rf ${outUsageDir} && ` + `$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + `${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`, CommandDeps: []string{ @@ -84,10 +143,18 @@ var r8, r8RE = remoteexec.MultiCommandStaticRules(pctx, "r8", ExecStrategy: "${config.RER8ExecStrategy}", Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, }, - }, []string{"outDir", "outDict", "r8Flags", "zipFlags"}, []string{"implicits"}) + "$zipUsageTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "tool", "name": "soong_zip"}, + Inputs: []string{"${config.SoongZipCmd}", "${outUsage}"}, + OutputFiles: []string{"${outUsageZip}"}, + ExecStrategy: "${config.RER8ExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + }, []string{"outDir", "outDict", "outUsage", "outUsageZip", "outUsageDir", + "r8Flags", "zipFlags"}, []string{"implicits"}) -func (j *Module) dexCommonFlags(ctx android.ModuleContext) []string { - flags := j.deviceProperties.Dxflags +func (d *dexer) dexCommonFlags(ctx android.ModuleContext, minSdkVersion sdkSpec) []string { + flags := d.dexProperties.Dxflags // Translate all the DX flags to D8 ones until all the build files have been migrated // to D8 flags. See: b/69377755 flags = android.RemoveListFromList(flags, @@ -103,30 +170,27 @@ func (j *Module) dexCommonFlags(ctx android.ModuleContext) []string { "--verbose") } - minSdkVersion, err := j.minSdkVersion().effectiveVersion(ctx) + effectiveVersion, err := minSdkVersion.effectiveVersion(ctx) if err != nil { ctx.PropertyErrorf("min_sdk_version", "%s", err) } - flags = append(flags, "--min-api "+minSdkVersion.asNumberString()) + flags = append(flags, "--min-api "+effectiveVersion.asNumberString()) return flags } -func (j *Module) d8Flags(ctx android.ModuleContext, flags javaBuilderFlags) ([]string, android.Paths) { - d8Flags := j.dexCommonFlags(ctx) - +func d8Flags(flags javaBuilderFlags) (d8Flags []string, d8Deps android.Paths) { d8Flags = append(d8Flags, flags.bootClasspath.FormRepeatedClassPath("--lib ")...) d8Flags = append(d8Flags, flags.classpath.FormRepeatedClassPath("--lib ")...) - var d8Deps android.Paths d8Deps = append(d8Deps, flags.bootClasspath...) d8Deps = append(d8Deps, flags.classpath...) return d8Flags, d8Deps } -func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Flags []string, r8Deps android.Paths) { - opt := j.deviceProperties.Optimize +func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Flags []string, r8Deps android.Paths) { + opt := d.dexProperties.Optimize // When an app contains references to APIs that are not in the SDK specified by // its LOCAL_SDK_VERSION for example added by support library or by runtime @@ -140,8 +204,6 @@ func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8F proguardRaiseDeps = append(proguardRaiseDeps, dep.(Dependency).HeaderJars()...) }) - r8Flags = append(r8Flags, j.dexCommonFlags(ctx)...) - r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars")) r8Flags = append(r8Flags, flags.bootClasspath.FormJavaClassPath("-libraryjars")) r8Flags = append(r8Flags, flags.classpath.FormJavaClassPath("-libraryjars")) @@ -154,15 +216,10 @@ func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8F android.PathForSource(ctx, "build/make/core/proguard.flags"), } - if j.shouldInstrumentStatic(ctx) { - flagFiles = append(flagFiles, - android.PathForSource(ctx, "build/make/core/proguard.jacoco.flags")) - } - - flagFiles = append(flagFiles, j.extraProguardFlagFiles...) + flagFiles = append(flagFiles, d.extraProguardFlagFiles...) // TODO(ccross): static android library proguard files - flagFiles = append(flagFiles, android.PathsForModuleSrc(ctx, j.deviceProperties.Optimize.Proguard_flags_files)...) + flagFiles = append(flagFiles, android.PathsForModuleSrc(ctx, opt.Proguard_flags_files)...) r8Flags = append(r8Flags, android.JoinWithPrefix(flagFiles.Strings(), "-include ")) r8Deps = append(r8Deps, flagFiles...) @@ -171,7 +228,7 @@ func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8F r8Deps = append(r8Deps, android.PathForSource(ctx, "build/make/core/proguard_basic_keeps.flags")) - r8Flags = append(r8Flags, j.deviceProperties.Optimize.Proguard_flags...) + r8Flags = append(r8Flags, opt.Proguard_flags...) // TODO(ccross): Don't shrink app instrumentation tests by default. if !Bool(opt.Shrink) { @@ -197,46 +254,55 @@ func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8F return r8Flags, r8Deps } -func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, +func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, minSdkVersion sdkSpec, classesJar android.Path, jarName string) android.ModuleOutPath { - useR8 := j.deviceProperties.EffectiveOptimizeEnabled() - // Compile classes.jar into classes.dex and then javalib.jar javalibJar := android.PathForModuleOut(ctx, "dex", jarName) outDir := android.PathForModuleOut(ctx, "dex") zipFlags := "--ignore_missing_files" - if proptools.Bool(j.deviceProperties.Uncompress_dex) { + if proptools.Bool(d.dexProperties.Uncompress_dex) { zipFlags += " -L 0" } + commonFlags := d.dexCommonFlags(ctx, minSdkVersion) + + useR8 := d.effectiveOptimizeEnabled() if useR8 { proguardDictionary := android.PathForModuleOut(ctx, "proguard_dictionary") - j.proguardDictionary = proguardDictionary - r8Flags, r8Deps := j.r8Flags(ctx, flags) + d.proguardDictionary = android.OptionalPathForPath(proguardDictionary) + proguardUsageDir := android.PathForModuleOut(ctx, "proguard_usage") + proguardUsage := proguardUsageDir.Join(ctx, ctx.Namespace().Path, + android.ModuleNameWithPossibleOverride(ctx), "unused.txt") + proguardUsageZip := android.PathForModuleOut(ctx, "proguard_usage.zip") + d.proguardUsageZip = android.OptionalPathForPath(proguardUsageZip) + r8Flags, r8Deps := d.r8Flags(ctx, flags) rule := r8 args := map[string]string{ - "r8Flags": strings.Join(r8Flags, " "), - "zipFlags": zipFlags, - "outDict": j.proguardDictionary.String(), - "outDir": outDir.String(), + "r8Flags": strings.Join(append(commonFlags, r8Flags...), " "), + "zipFlags": zipFlags, + "outDict": proguardDictionary.String(), + "outUsageDir": proguardUsageDir.String(), + "outUsage": proguardUsage.String(), + "outUsageZip": proguardUsageZip.String(), + "outDir": outDir.String(), } if ctx.Config().IsEnvTrue("RBE_R8") { rule = r8RE args["implicits"] = strings.Join(r8Deps.Strings(), ",") } ctx.Build(pctx, android.BuildParams{ - Rule: rule, - Description: "r8", - Output: javalibJar, - ImplicitOutput: proguardDictionary, - Input: classesJar, - Implicits: r8Deps, - Args: args, + Rule: rule, + Description: "r8", + Output: javalibJar, + ImplicitOutputs: android.WritablePaths{proguardDictionary, proguardUsageZip}, + Input: classesJar, + Implicits: r8Deps, + Args: args, }) } else { - d8Flags, d8Deps := j.d8Flags(ctx, flags) + d8Flags, d8Deps := d8Flags(flags) rule := d8 if ctx.Config().IsEnvTrue("RBE_D8") { rule = d8RE @@ -248,13 +314,13 @@ func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, Input: classesJar, Implicits: d8Deps, Args: map[string]string{ - "d8Flags": strings.Join(d8Flags, " "), + "d8Flags": strings.Join(append(commonFlags, d8Flags...), " "), "zipFlags": zipFlags, "outDir": outDir.String(), }, }) } - if proptools.Bool(j.deviceProperties.Uncompress_dex) { + if proptools.Bool(d.dexProperties.Uncompress_dex) { alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", jarName) TransformZipAlign(ctx, alignedJavalibJar, javalibJar) javalibJar = alignedJavalibJar diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 28a2c8ae6..f1b717874 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -37,7 +37,7 @@ type dexpreopter struct { usesLibs []string optionalUsesLibs []string enforceUsesLibs bool - libraryPaths map[string]android.Path + libraryPaths dexpreopt.LibraryPaths builtInstalled string } @@ -77,10 +77,6 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool { return true } - if ctx.Config().UnbundledBuild() { - return true - } - if d.isTest { return true } @@ -131,7 +127,8 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo global := dexpreopt.GetGlobalConfig(ctx) bootImage := defaultBootImageConfig(ctx) dexFiles := bootImage.dexPathsDeps.Paths() - dexLocations := bootImage.dexLocationsDeps + // The dex locations for all Android variants are identical. + dexLocations := bootImage.getAnyAndroidVariant().dexLocationsDeps if global.UseArtImage { bootImage = artBootImageConfig(ctx) } @@ -159,6 +156,8 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo images = append(images, variant.images) imagesDeps = append(imagesDeps, variant.imagesDeps) } + // The image locations for all Android variants are identical. + imageLocations := bootImage.getAnyAndroidVariant().imageLocations() dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath) @@ -174,7 +173,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo profileBootListing = android.ExistentPathForSource(ctx, ctx.ModuleDir(), String(d.dexpreoptProperties.Dex_preopt.Profile)+"-boot") profileIsTextListing = true - } else { + } else if global.ProfileDir != "" { profileClassListing = android.ExistentPathForSource(ctx, global.ProfileDir, ctx.ModuleName()+".prof") } @@ -194,15 +193,15 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo ProfileIsTextListing: profileIsTextListing, ProfileBootListing: profileBootListing, - EnforceUsesLibraries: d.enforceUsesLibs, - PresentOptionalUsesLibraries: d.optionalUsesLibs, - UsesLibraries: d.usesLibs, - LibraryPaths: d.libraryPaths, + EnforceUsesLibraries: d.enforceUsesLibs, + OptionalUsesLibraries: d.optionalUsesLibs, + UsesLibraries: d.usesLibs, + LibraryPaths: d.libraryPaths, Archs: archs, DexPreoptImages: images, DexPreoptImagesDeps: imagesDeps, - DexPreoptImageLocations: bootImage.imageLocations, + DexPreoptImageLocations: imageLocations, PreoptBootClassPathDexFiles: dexFiles, PreoptBootClassPathDexLocations: dexLocations, diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 2f0cbdb8c..3addc1a74 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -29,29 +29,10 @@ func init() { RegisterDexpreoptBootJarsComponents(android.InitRegistrationContext) } -// The image "location" is a symbolic path that with multiarchitecture -// support doesn't really exist on the device. Typically it is -// /system/framework/boot.art and should be the same for all supported -// architectures on the device. The concrete architecture specific -// content actually ends up in a "filename" that contains an -// architecture specific directory name such as arm, arm64, mips, -// mips64, x86, x86_64. -// -// Here are some example values for an x86_64 / x86 configuration: -// -// bootImages["x86_64"] = "out/soong/generic_x86_64/dex_bootjars/system/framework/x86_64/boot.art" -// dexpreopt.PathToLocation(bootImages["x86_64"], "x86_64") = "out/soong/generic_x86_64/dex_bootjars/system/framework/boot.art" -// -// bootImages["x86"] = "out/soong/generic_x86_64/dex_bootjars/system/framework/x86/boot.art" -// dexpreopt.PathToLocation(bootImages["x86"])= "out/soong/generic_x86_64/dex_bootjars/system/framework/boot.art" -// -// The location is passed as an argument to the ART tools like dex2oat instead of the real path. The ART tools -// will then reconstruct the real path, so the rules must have a dependency on the real path. - // Target-independent description of pre-compiled boot image. type bootImageConfig struct { - // Whether this image is an extension. - extension bool + // If this image is an extension, the image that it extends. + extends *bootImageConfig // Image name (used in directory names and ninja rule names). name string @@ -68,20 +49,13 @@ type bootImageConfig struct { // Subdirectory where the image files are installed. installSubdir string - // The names of jars that constitute this image. - modules []string - - // The "locations" of jars. - dexLocations []string // for this image - dexLocationsDeps []string // for the dependency images and in this image + // A list of (location, jar) pairs for the Java modules in this image. + modules android.ConfiguredJarList // File paths to jars. dexPaths android.WritablePaths // for this image dexPathsDeps android.WritablePaths // for the dependency images and in this image - // The "locations" of the dependency images and in this image. - imageLocations []string - // File path to a zip archive with all image files (or nil, if not needed). zip android.WritablePath @@ -99,6 +73,10 @@ type bootImageVariant struct { // Target for which the image is generated. target android.Target + // The "locations" of jars. + dexLocations []string // for this image + dexLocationsDeps []string // for the dependency images and in this image + // Paths to image files. images android.OutputPath // first image file imagesDeps android.OutputPaths // all files @@ -121,30 +99,40 @@ func (image bootImageConfig) getVariant(target android.Target) *bootImageVariant return nil } -func (image bootImageConfig) moduleName(idx int) string { +// Return any (the first) variant which is for the device (as opposed to for the host) +func (image bootImageConfig) getAnyAndroidVariant() *bootImageVariant { + for _, variant := range image.variants { + if variant.target.Os == android.Android { + return variant + } + } + return nil +} + +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 := image.modules[idx] + m := image.modules.Jar(idx) name := image.stem - if idx != 0 || image.extension { - name += "-" + stemOf(m) + if idx != 0 || image.extends != nil { + name += "-" + android.ModuleStem(m) } return name } -func (image bootImageConfig) firstModuleNameOrStem() string { - if len(image.modules) > 0 { - return image.moduleName(0) +func (image bootImageConfig) firstModuleNameOrStem(ctx android.PathContext) string { + if image.modules.Len() > 0 { + return image.moduleName(ctx, 0) } else { return image.stem } } 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) + ret := make(android.OutputPaths, 0, image.modules.Len()*len(exts)) + for i := 0; i < image.modules.Len(); i++ { + name := image.moduleName(ctx, i) for _, ext := range exts { ret = append(ret, dir.Join(ctx, name+ext)) } @@ -152,6 +140,24 @@ func (image bootImageConfig) moduleFiles(ctx android.PathContext, dir android.Ou return ret } +// The image "location" is a symbolic path that, with multiarchitecture support, doesn't really +// exist on the device. Typically it is /apex/com.android.art/javalib/boot.art and should be the +// same for all supported architectures on the device. The concrete architecture specific files +// actually end up in architecture-specific sub-directory such as arm, arm64, x86, or x86_64. +// +// For example a physical file +// "/apex/com.android.art/javalib/x86/boot.art" has "image location" +// "/apex/com.android.art/javalib/boot.art" (which is not an actual file). +// +// The location is passed as an argument to the ART tools like dex2oat instead of the real path. +// ART tools will then reconstruct the architecture-specific real path. +func (image *bootImageVariant) imageLocations() (imageLocations []string) { + if image.extends != nil { + imageLocations = image.extends.getVariant(image.target).imageLocations() + } + return append(imageLocations, dexpreopt.PathToLocation(image.images, image.target.Arch.ArchType)) +} + func concat(lists ...[]string) []string { var size int for _, l := range lists { @@ -173,20 +179,7 @@ func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) { } func skipDexpreoptBootJars(ctx android.PathContext) bool { - if dexpreopt.GetGlobalConfig(ctx).DisablePreopt { - return true - } - - if ctx.Config().UnbundledBuild() { - return true - } - - if len(ctx.Config().Targets[android.Android]) == 0 { - // Host-only build - return true - } - - return false + return dexpreopt.GetGlobalConfig(ctx).DisablePreopt } type dexpreoptBootJars struct { @@ -204,7 +197,10 @@ func DexpreoptedArtApexJars(ctx android.BuilderContext) map[android.ArchType]and // Include dexpreopt files for the primary boot image. files := map[android.ArchType]android.OutputPaths{} for _, variant := range artBootImageConfig(ctx).variants { - files[variant.target.Arch.ArchType] = variant.imagesDeps + // We also generate boot images for host (for testing), but we don't need those in the apex. + if variant.target.Os == android.Android { + files[variant.target.Arch.ArchType] = variant.imagesDeps + } } return files } @@ -251,13 +247,13 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul return -1, nil } - jar, hasJar := module.(interface{ DexJar() android.Path }) + jar, hasJar := module.(interface{ DexJarBuildPath() android.Path }) if !hasJar { return -1, nil } name := ctx.ModuleName(module) - index := android.IndexList(name, image.modules) + index := image.modules.IndexOfJar(name) if index == -1 { return -1, nil } @@ -266,7 +262,7 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul apex, isApexModule := module.(android.ApexModule) fromUpdatableApex := isApexModule && apex.Updatable() if image.name == artBootImageName { - if isApexModule && strings.HasPrefix(apex.ApexName(), "com.android.art.") { + if isApexModule && len(apex.InApexes()) > 0 && allHavePrefix(apex.InApexes(), "com.android.art.") { // ok: found the jar in the ART apex } else if isApexModule && apex.IsForPlatform() && Bool(module.(*Library).deviceProperties.Hostdex) { // exception (skip and continue): special "hostdex" platform variant @@ -276,30 +272,39 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul return -1, nil } else if fromUpdatableApex { // error: this jar is part of an updatable apex other than ART - ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the ART boot image", name, apex.ApexName()) + ctx.Errorf("module %q from updatable apexes %q is not allowed in the ART boot image", name, apex.InApexes()) } else { // error: this jar is part of the platform or a non-updatable apex - ctx.Errorf("module '%s' is not allowed in the ART boot image", name) + ctx.Errorf("module %q is not allowed in the ART boot image", name) } } else if image.name == frameworkBootImageName { if !fromUpdatableApex { // ok: this jar is part of the platform or a non-updatable apex } else { // error: this jar is part of an updatable apex - ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the framework boot image", name, apex.ApexName()) + ctx.Errorf("module %q from updatable apexes %q is not allowed in the framework boot image", name, apex.InApexes()) } } else { panic("unknown boot image: " + image.name) } - return index, jar.DexJar() + return index, jar.DexJarBuildPath() +} + +func allHavePrefix(list []string, prefix string) bool { + for _, s := range list { + if !strings.HasPrefix(s, prefix) { + return false + } + } + return true } // buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image. func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig { // Collect dex jar paths for the boot image modules. // This logic is tested in the apex package to avoid import cycle apex <-> java. - bootDexJars := make(android.Paths, len(image.modules)) + bootDexJars := make(android.Paths, image.modules.Len()) ctx.VisitAllModules(func(module android.Module) { if i, j := getBootImageJar(ctx, image, module); i != -1 { bootDexJars[i] = j @@ -310,13 +315,13 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootI // Ensure all modules were converted to paths for i := range bootDexJars { if bootDexJars[i] == nil { + m := image.modules.Jar(i) if ctx.Config().AllowMissingDependencies() { - missingDeps = append(missingDeps, image.modules[i]) + missingDeps = append(missingDeps, m) bootDexJars[i] = android.PathForOutput(ctx, "missing") } else { ctx.Errorf("failed to find a dex jar path for module '%s'"+ - ", note that some jars may be filtered out by module constraints", - image.modules[i]) + ", note that some jars may be filtered out by module constraints", m) } } } @@ -336,10 +341,12 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootI bootFrameworkProfileRule(ctx, image, missingDeps) updatableBcpPackagesRule(ctx, image, missingDeps) - var allFiles android.Paths + var zipFiles android.Paths for _, variant := range image.variants { files := buildBootImageVariant(ctx, variant, profile, missingDeps) - allFiles = append(allFiles, files.Paths()...) + if variant.target.Os == android.Android { + zipFiles = append(zipFiles, files.Paths()...) + } } if image.zip != nil { @@ -347,8 +354,8 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootI rule.Command(). BuiltTool(ctx, "soong_zip"). FlagWithOutput("-o ", image.zip). - FlagWithArg("-C ", image.dir.String()). - FlagWithInputList("-f ", allFiles, " -f ") + FlagWithArg("-C ", image.dir.Join(ctx, android.Android.String()).String()). + FlagWithInputList("-f ", zipFiles, " -f ") rule.Build(pctx, ctx, "zip_"+image.name, "zip "+image.name+" image") } @@ -363,9 +370,10 @@ func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant global := dexpreopt.GetGlobalConfig(ctx) arch := image.target.Arch.ArchType - symbolsDir := image.symbolsDir.Join(ctx, image.installSubdir, arch.String()) + os := image.target.Os.String() // We need to distinguish host-x86 and device-x86. + symbolsDir := image.symbolsDir.Join(ctx, os, image.installSubdir, arch.String()) symbolsFile := symbolsDir.Join(ctx, image.stem+".oat") - outputDir := image.dir.Join(ctx, image.installSubdir, arch.String()) + outputDir := image.dir.Join(ctx, os, image.installSubdir, arch.String()) outputPath := outputDir.Join(ctx, image.stem+".oat") oatLocation := dexpreopt.PathToLocation(outputPath, arch) imagePath := outputPath.ReplaceExtension(ctx, "art") @@ -411,7 +419,7 @@ func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant cmd.FlagWithInput("--dirty-image-objects=", global.DirtyImageObjects.Path()) } - if image.extension { + if image.extends != nil { artImage := image.primaryImages cmd. Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", image.dexPathsDeps.Paths(), ":"). @@ -433,13 +441,18 @@ func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant FlagWithArg("--oat-location=", oatLocation). FlagWithArg("--image=", imagePath.String()). FlagWithArg("--instruction-set=", arch.String()). - FlagWithArg("--instruction-set-variant=", global.CpuVariant[arch]). - FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch]). FlagWithArg("--android-root=", global.EmptyDirectory). FlagWithArg("--no-inline-from=", "core-oj.jar"). Flag("--force-determinism"). Flag("--abort-on-hard-verifier-error") + // Use the default variant/features for host builds. + // The map below contains only device CPU info (which might be x86 on some devices). + if image.target.Os == android.Android { + cmd.FlagWithArg("--instruction-set-variant=", global.CpuVariant[arch]) + cmd.FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch]) + } + if global.BootFlags != "" { cmd.Flag(global.BootFlags) } @@ -451,7 +464,6 @@ func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant cmd.Textf(`|| ( echo %s ; false )`, proptools.ShellEscape(failureMessage)) installDir := filepath.Join("/", image.installSubdir, arch.String()) - vdexInstallDir := filepath.Join("/", image.installSubdir) var vdexInstalls android.RuleBuilderInstalls var unstrippedInstalls android.RuleBuilderInstalls @@ -470,11 +482,10 @@ func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant cmd.ImplicitOutput(vdex) zipFiles = append(zipFiles, vdex) - // The vdex files are identical between architectures, install them to a shared location. The Make rules will - // only use the install rules for one architecture, and will create symlinks into the architecture-specific - // directories. + // Note that the vdex files are identical between architectures. + // Make rules will create symlinks to share them between architectures. vdexInstalls = append(vdexInstalls, - android.RuleBuilderInstall{vdex, filepath.Join(vdexInstallDir, vdex.Base())}) + android.RuleBuilderInstall{vdex, filepath.Join(installDir, vdex.Base())}) } for _, unstrippedOat := range image.moduleFiles(ctx, symbolsDir, ".oat") { @@ -485,7 +496,7 @@ func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant android.RuleBuilderInstall{unstrippedOat, filepath.Join(installDir, unstrippedOat.Base())}) } - rule.Build(pctx, ctx, image.name+"JarsDexpreopt_"+arch.String(), "dexpreopt "+image.name+" jars "+arch.String()) + rule.Build(pctx, ctx, image.name+"JarsDexpreopt_"+image.target.String(), "dexpreopt "+image.name+" jars "+arch.String()) // save output and installed files for makevars image.installs = rule.Installs() @@ -503,7 +514,7 @@ func bootImageProfileRule(ctx android.SingletonContext, image *bootImageConfig, globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx) global := dexpreopt.GetGlobalConfig(ctx) - if global.DisableGenerateProfile || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() { + if global.DisableGenerateProfile || ctx.Config().UnbundledBuild() { return nil } profile := ctx.Config().Once(bootImageProfileRuleKey, func() interface{} { @@ -535,7 +546,7 @@ func bootImageProfileRule(ctx android.SingletonContext, image *bootImageConfig, Tool(globalSoong.Profman). FlagWithInput("--create-profile-from=", bootImageProfile). FlagForEachInput("--apk=", image.dexPathsDeps.Paths()). - FlagForEachArg("--dex-location=", image.dexLocationsDeps). + FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps). FlagWithOutput("--reference-profile-file=", profile) rule.Install(profile, "/system/etc/boot-image.prof") @@ -558,7 +569,7 @@ func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImageConf globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx) global := dexpreopt.GetGlobalConfig(ctx) - if global.DisableGenerateProfile || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() { + if global.DisableGenerateProfile || ctx.Config().UnbundledBuild() { return nil } return ctx.Config().Once(bootFrameworkProfileRuleKey, func() interface{} { @@ -586,7 +597,7 @@ func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImageConf Flag("--generate-boot-profile"). FlagWithInput("--create-profile-from=", bootFrameworkProfile). FlagForEachInput("--apk=", image.dexPathsDeps.Paths()). - FlagForEachArg("--dex-location=", image.dexLocationsDeps). + FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps). FlagWithOutput("--reference-profile-file=", profile) rule.Install(profile, "/system/etc/boot-image.bprof") @@ -600,13 +611,13 @@ func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImageConf var bootFrameworkProfileRuleKey = android.NewOnceKey("bootFrameworkProfileRule") func updatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath { - if ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() { + if ctx.Config().UnbundledBuild() { return nil } return ctx.Config().Once(updatableBcpPackagesRuleKey, func() interface{} { global := dexpreopt.GetGlobalConfig(ctx) - updatableModules := dexpreopt.GetJarsFromApexJarPairs(global.UpdatableBootJars) + updatableModules := global.UpdatableBootJars.CopyOfJars() // Collect `permitted_packages` for updatable boot jars. var updatablePackages []string @@ -658,27 +669,32 @@ func dumpOatRules(ctx android.SingletonContext, image *bootImageConfig) { var allPhonies android.Paths for _, image := range image.variants { arch := image.target.Arch.ArchType + suffix := arch.String() + // Host and target might both use x86 arch. We need to ensure the names are unique. + if image.target.Os.Class == android.Host { + suffix = "host-" + suffix + } // Create a rule to call oatdump. - output := android.PathForOutput(ctx, "boot."+arch.String()+".oatdump.txt") + output := android.PathForOutput(ctx, "boot."+suffix+".oatdump.txt") rule := android.NewRuleBuilder() rule.Command(). // TODO: for now, use the debug version for better error reporting BuiltTool(ctx, "oatdumpd"). FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":"). FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":"). - FlagWithArg("--image=", strings.Join(image.imageLocations, ":")).Implicits(image.imagesDeps.Paths()). + FlagWithArg("--image=", strings.Join(image.imageLocations(), ":")).Implicits(image.imagesDeps.Paths()). FlagWithOutput("--output=", output). FlagWithArg("--instruction-set=", arch.String()) - rule.Build(pctx, ctx, "dump-oat-boot-"+arch.String(), "dump oat boot "+arch.String()) + rule.Build(pctx, ctx, "dump-oat-boot-"+suffix, "dump oat boot "+arch.String()) // Create a phony rule that depends on the output file and prints the path. - phony := android.PathForPhony(ctx, "dump-oat-boot-"+arch.String()) + phony := android.PathForPhony(ctx, "dump-oat-boot-"+suffix) rule = android.NewRuleBuilder() rule.Command(). Implicit(output). ImplicitOutput(phony). Text("echo").FlagWithArg("Output in ", output.String()) - rule.Build(pctx, ctx, "phony-dump-oat-boot-"+arch.String(), "dump oat boot "+arch.String()) + rule.Build(pctx, ctx, "phony-dump-oat-boot-"+suffix, "dump oat boot "+arch.String()) allPhonies = append(allPhonies, phony) } @@ -716,21 +732,25 @@ func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) { if image != nil { ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String()) ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(image.dexPathsDeps.Strings(), " ")) - ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.dexLocationsDeps, " ")) + ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.getAnyAndroidVariant().dexLocationsDeps, " ")) var imageNames []string for _, current := range append(d.otherImages, image) { imageNames = append(imageNames, current.name) - for _, current := range current.variants { - sfx := current.name + "_" + current.target.Arch.ArchType.String() - ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, current.vdexInstalls.String()) - ctx.Strict("DEXPREOPT_IMAGE_"+sfx, current.images.String()) - ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(current.imagesDeps.Strings(), " ")) - ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, current.installs.String()) - ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, current.unstrippedInstalls.String()) + for _, variant := range current.variants { + suffix := "" + if variant.target.Os.Class == android.Host { + suffix = "_host" + } + sfx := variant.name + suffix + "_" + variant.target.Arch.ArchType.String() + ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, variant.vdexInstalls.String()) + ctx.Strict("DEXPREOPT_IMAGE_"+sfx, variant.images.String()) + ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(variant.imagesDeps.Strings(), " ")) + ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, variant.installs.String()) + ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, variant.unstrippedInstalls.String()) } - - ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(current.imageLocations, ":")) + imageLocations := current.getAnyAndroidVariant().imageLocations() + ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(imageLocations, ":")) ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+current.name, current.zip.String()) } ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(imageNames, " ")) diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go index e7b3c3ba9..4a8d3cd50 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", @@ -48,67 +48,88 @@ func TestDexpreoptBootJars(t *testing.T) { pathCtx := android.PathContextForTesting(config) dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx) - dexpreoptConfig.BootJars = []string{"foo", "bar", "baz"} + dexpreoptConfig.BootJars = android.CreateConfiguredJarList(pathCtx, []string{"platform:foo", "platform:bar", "platform:baz"}) 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/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) } - expectedOutputs := []string{ - "dex_bootjars/system/framework/arm64/boot.invocation", - - "dex_bootjars/system/framework/arm64/boot-foo.art", - "dex_bootjars/system/framework/arm64/boot-bar.art", - "dex_bootjars/system/framework/arm64/boot-baz.art", - - "dex_bootjars/system/framework/arm64/boot-foo.oat", - "dex_bootjars/system/framework/arm64/boot-bar.oat", - "dex_bootjars/system/framework/arm64/boot-baz.oat", + if !reflect.DeepEqual(outputs, expectedOutputs) { + t.Errorf("want outputs %q\n got outputs %q", expectedOutputs, outputs) + } +} - "dex_bootjars/system/framework/arm64/boot-foo.vdex", - "dex_bootjars/system/framework/arm64/boot-bar.vdex", - "dex_bootjars/system/framework/arm64/boot-baz.vdex", +func TestDexpreoptBootJars(t *testing.T) { + ruleFile := "boot-foo.art" - "dex_bootjars_unstripped/system/framework/arm64/boot-foo.oat", - "dex_bootjars_unstripped/system/framework/arm64/boot-bar.oat", - "dex_bootjars_unstripped/system/framework/arm64/boot-baz.oat", + 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", } - for i := range expectedOutputs { - expectedOutputs[i] = filepath.Join(buildDir, "test_device", expectedOutputs[i]) + 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", } - outputs := append(android.WritablePaths{bootArt.Output}, bootArt.ImplicitOutputs...).Strings() - sort.Strings(outputs) - sort.Strings(expectedOutputs) + testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs) +} - if !reflect.DeepEqual(outputs, expectedOutputs) { - t.Errorf("want outputs %q\n got outputs %q", expectedOutputs, outputs) +// 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 ctx.Config().Targets[android.Android] { + 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)) + } + } } + + expectedOutputs := []string{ + "dex_bootjars/boot.zip", + } + + testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs) } diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go index f8356d188..f0d82ff92 100644 --- a/java/dexpreopt_config.go +++ b/java/dexpreopt_config.go @@ -37,14 +37,12 @@ func systemServerClasspath(ctx android.MakeVarsContext) []string { filepath.Join("/system/framework", m+".jar")) } // 2) The jars that are from an updatable apex. - for _, m := range global.UpdatableSystemServerJars { - systemServerClasspathLocations = append(systemServerClasspathLocations, - dexpreopt.GetJarLocationFromApexJarPair(m)) - } - if len(systemServerClasspathLocations) != len(global.SystemServerJars)+len(global.UpdatableSystemServerJars) { + systemServerClasspathLocations = append(systemServerClasspathLocations, + global.UpdatableSystemServerJars.DevicePaths(ctx.Config(), android.Android)...) + if len(systemServerClasspathLocations) != len(global.SystemServerJars)+global.UpdatableSystemServerJars.Len() { panic(fmt.Errorf("Wrong number of system server jars, got %d, expected %d", len(systemServerClasspathLocations), - len(global.SystemServerJars)+len(global.UpdatableSystemServerJars))) + len(global.SystemServerJars)+global.UpdatableSystemServerJars.Len())) } return systemServerClasspathLocations }) @@ -61,20 +59,14 @@ func dexpreoptTargets(ctx android.PathContext) []android.Target { targets = append(targets, target) } } + // We may also need the images on host in order to run host-based tests. + for _, target := range ctx.Config().Targets[android.BuildOs] { + targets = append(targets, target) + } return targets } -func stemOf(moduleName string) string { - // b/139391334: the stem of framework-minus-apex is framework - // This is hard coded here until we find a good way to query the stem - // of a module before any other mutators are run - if moduleName == "framework-minus-apex" { - return "framework" - } - return moduleName -} - var ( bootImageConfigKey = android.NewOnceKey("bootImageConfig") artBootImageName = "art" @@ -89,47 +81,34 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig { targets := dexpreoptTargets(ctx) deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName()) - artModules := global.ArtApexJars + artModules := global.ArtApexJars.CopyOf() // With EMMA_INSTRUMENT_FRAMEWORK=true the Core libraries depend on jacoco. if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") { - artModules = append(artModules, "jacocoagent") + artModules.Append("com.android.art", "jacocoagent") } - frameworkModules := android.RemoveListFromList(global.BootJars, - concat(artModules, dexpreopt.GetJarsFromApexJarPairs(global.UpdatableBootJars))) + frameworkModules := global.BootJars.CopyOf() + frameworkModules.RemoveList(artModules) artSubdir := "apex/com.android.art/javalib" frameworkSubdir := "system/framework" - var artLocations, frameworkLocations []string - for _, m := range artModules { - artLocations = append(artLocations, filepath.Join("/"+artSubdir, stemOf(m)+".jar")) - } - for _, m := range frameworkModules { - frameworkLocations = append(frameworkLocations, filepath.Join("/"+frameworkSubdir, stemOf(m)+".jar")) - } - // ART config for the primary boot image in the ART apex. // It includes the Core Libraries. artCfg := bootImageConfig{ - extension: false, - name: artBootImageName, - stem: "boot", - installSubdir: artSubdir, - modules: artModules, - dexLocations: artLocations, - dexLocationsDeps: artLocations, + name: artBootImageName, + stem: "boot", + installSubdir: artSubdir, + modules: artModules, } // Framework config for the boot image extension. // It includes framework libraries and depends on the ART config. frameworkCfg := bootImageConfig{ - extension: true, - name: frameworkBootImageName, - stem: "boot", - installSubdir: frameworkSubdir, - modules: frameworkModules, - dexLocations: frameworkLocations, - dexLocationsDeps: append(artLocations, frameworkLocations...), + extends: &artCfg, + name: frameworkBootImageName, + stem: "boot", + installSubdir: frameworkSubdir, + modules: frameworkModules, } configs := map[string]*bootImageConfig{ @@ -143,30 +122,28 @@ 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" - - c.imageLocations = []string{c.dir.Join(ctx, c.installSubdir, imageName).String()} + 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. // Set up known paths for them, the singleton rules will copy them there. // TODO(b/143682396): use module dependencies instead inputDir := deviceDir.Join(ctx, "dex_"+c.name+"jars_input") - for _, m := range c.modules { - c.dexPaths = append(c.dexPaths, inputDir.Join(ctx, stemOf(m)+".jar")) - } + c.dexPaths = c.modules.BuildPaths(ctx, inputDir) c.dexPathsDeps = c.dexPaths // Create target-specific variants. for _, target := range targets { arch := target.Arch.ArchType - imageDir := c.dir.Join(ctx, c.installSubdir, arch.String()) + imageDir := c.dir.Join(ctx, target.Os.String(), c.installSubdir, arch.String()) variant := &bootImageVariant{ bootImageConfig: c, target: target, images: imageDir.Join(ctx, imageName), imagesDeps: c.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex"), + dexLocations: c.modules.DevicePaths(ctx.Config(), target.Os), } + variant.dexLocationsDeps = variant.dexLocations c.variants = append(c.variants, variant) } @@ -177,8 +154,8 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig { frameworkCfg.dexPathsDeps = append(artCfg.dexPathsDeps, frameworkCfg.dexPathsDeps...) for i := range targets { frameworkCfg.variants[i].primaryImages = artCfg.variants[i].images + frameworkCfg.variants[i].dexLocationsDeps = append(artCfg.variants[i].dexLocations, frameworkCfg.variants[i].dexLocationsDeps...) } - frameworkCfg.imageLocations = append(artCfg.imageLocations, frameworkCfg.imageLocations...) return configs }).(map[string]*bootImageConfig) @@ -197,12 +174,9 @@ func defaultBootclasspath(ctx android.PathContext) []string { global := dexpreopt.GetGlobalConfig(ctx) image := defaultBootImageConfig(ctx) - updatableBootclasspath := make([]string, len(global.UpdatableBootJars)) - for i, p := range global.UpdatableBootJars { - updatableBootclasspath[i] = dexpreopt.GetJarLocationFromApexJarPair(p) - } + updatableBootclasspath := global.UpdatableBootJars.DevicePaths(ctx.Config(), android.Android) - bootclasspath := append(copyOf(image.dexLocationsDeps), updatableBootclasspath...) + bootclasspath := append(copyOf(image.getAnyAndroidVariant().dexLocationsDeps), updatableBootclasspath...) return bootclasspath }) } @@ -217,8 +191,8 @@ func init() { func dexpreoptConfigMakevars(ctx android.MakeVarsContext) { ctx.Strict("PRODUCT_BOOTCLASSPATH", strings.Join(defaultBootclasspath(ctx), ":")) - ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).dexLocationsDeps, ":")) + ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).getAnyAndroidVariant().dexLocationsDeps, ":")) ctx.Strict("PRODUCT_SYSTEM_SERVER_CLASSPATH", strings.Join(systemServerClasspath(ctx), ":")) - ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules, ":")) + ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules.CopyOfApexJarPairs(), ":")) } diff --git a/java/droiddoc.go b/java/droiddoc.go index 230b1f026..3b192ba55 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -112,13 +112,20 @@ type JavadocProperties struct { // local files that are used within user customized droiddoc options. Arg_files []string `android:"path"` - // user customized droiddoc args. + // user customized droiddoc args. Deprecated, use flags instead. // Available variables for substitution: // // $(location <label>): the path to the arg_files with name <label> // $$: a literal $ Args *string + // user customized droiddoc args. Not compatible with property args. + // Available variables for substitution: + // + // $(location <label>): the path to the arg_files with name <label> + // $$: a literal $ + Flags []string + // names of the output files used in args that will be generated Out []string @@ -191,7 +198,7 @@ type DroiddocProperties struct { // the generated removed Dex API filename by Doclava. Removed_dex_api_filename *string - // if set to false, don't allow droiddoc to generate stubs source files. Defaults to true. + // if set to false, don't allow droiddoc to generate stubs source files. Defaults to false. Create_stubs *bool Check_api struct { @@ -287,6 +294,9 @@ type DroidstubsProperties struct { // the dirs which Metalava extracts API levels annotations from. Api_levels_annotations_dirs []string + // the filename which Metalava extracts API levels annotations from. Defaults to android.jar. + Api_levels_jar_filename *string + // if set to true, collect the values used by the Dev tools and // write them in files packaged with the SDK. Defaults to false. Write_sdk_values *bool @@ -382,7 +392,7 @@ type Javadoc struct { argFiles android.Paths implicits android.Paths - args string + args []string docZip android.WritablePath stubsSrcJar android.WritablePath @@ -440,16 +450,11 @@ func (j *Javadoc) targetSdkVersion() sdkSpec { func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) { if ctx.Device() { sdkDep := decodeSdkDep(ctx, sdkContext(j)) - if sdkDep.useDefaultLibs { - ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...) - ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules) - if sdkDep.hasFrameworkLibs() { - ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...) - } - } else if sdkDep.useModule { + if sdkDep.useModule { ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...) ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules) ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...) + ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...) } } @@ -624,8 +629,8 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { } srcFiles = filterHtml(srcFiles) - flags := j.collectAidlFlags(ctx, deps) - srcFiles = j.genSources(ctx, srcFiles, flags) + aidlFlags := j.collectAidlFlags(ctx, deps) + srcFiles = j.genSources(ctx, srcFiles, aidlFlags) // srcs may depend on some genrule output. j.srcJars = srcFiles.FilterByExt(".srcjar") @@ -654,24 +659,38 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { } } - var err error - j.args, err = android.Expand(String(j.properties.Args), func(name string) (string, error) { - if strings.HasPrefix(name, "location ") { - label := strings.TrimSpace(strings.TrimPrefix(name, "location ")) - if paths, ok := argFilesMap[label]; ok { - return paths, nil - } else { - return "", fmt.Errorf("unknown location label %q, expecting one of %q", - label, strings.Join(argFileLabels, ", ")) + var argsPropertyName string + flags := make([]string, 0) + if j.properties.Args != nil && j.properties.Flags != nil { + ctx.PropertyErrorf("args", "flags is set. Cannot set args") + } else if args := proptools.String(j.properties.Args); args != "" { + flags = append(flags, args) + argsPropertyName = "args" + } else { + flags = append(flags, j.properties.Flags...) + argsPropertyName = "flags" + } + + for _, flag := range flags { + args, err := android.Expand(flag, func(name string) (string, error) { + if strings.HasPrefix(name, "location ") { + label := strings.TrimSpace(strings.TrimPrefix(name, "location ")) + if paths, ok := argFilesMap[label]; ok { + return paths, nil + } else { + return "", fmt.Errorf("unknown location label %q, expecting one of %q", + label, strings.Join(argFileLabels, ", ")) + } + } else if name == "genDir" { + return android.PathForModuleGen(ctx).String(), nil } - } else if name == "genDir" { - return android.PathForModuleGen(ctx).String(), nil - } - return "", fmt.Errorf("unknown variable '$(%s)'", name) - }) + return "", fmt.Errorf("unknown variable '$(%s)'", name) + }) - if err != nil { - ctx.PropertyErrorf("args", "%s", err.Error()) + if err != nil { + ctx.PropertyErrorf(argsPropertyName, "%s", err.Error()) + } + j.args = append(j.args, args) } return deps @@ -854,6 +873,10 @@ func (d *Droiddoc) doclavaDocsFlags(ctx android.ModuleContext, cmd *android.Rule } } +func (d *Droiddoc) createStubs() bool { + return BoolDefault(d.properties.Create_stubs, false) +} + func (d *Droiddoc) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) { if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") || @@ -876,7 +899,7 @@ func (d *Droiddoc) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilde cmd.FlagWithOutput("-removedDexApi ", d.removedDexApiFile) } - if BoolDefault(d.properties.Create_stubs, true) { + if d.createStubs() { cmd.FlagWithArg("-stubs ", stubsDir.String()) } @@ -1015,7 +1038,7 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { d.stubsFlags(ctx, cmd, stubsDir) - cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles) + cmd.Flag(strings.Join(d.Javadoc.args, " ")).Implicits(d.Javadoc.argFiles) if d.properties.Compat_config != nil { compatConfig := android.PathForModuleSrc(ctx, String(d.properties.Compat_config)) @@ -1058,9 +1081,7 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { rule.Build(pctx, ctx, "javadoc", desc) - if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") && - !ctx.Config().IsPdkBuild() { - + if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") { apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file)) removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file)) @@ -1127,9 +1148,7 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { rule.Build(pctx, ctx, "doclavaCurrentApiUpdate", "update current API") } - if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") && - !ctx.Config().IsPdkBuild() { - + if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") { apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file)) removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file)) @@ -1332,7 +1351,7 @@ func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.Ru cmd.Flag("--include-annotations") validatingNullability := - strings.Contains(d.Javadoc.args, "--validate-nullability-from-merged-stubs") || + android.InList("--validate-nullability-from-merged-stubs", d.Javadoc.args) || String(d.properties.Validate_nullability_from_list) != "" migratingNullability := String(d.properties.Previous_api) != "" @@ -1387,38 +1406,41 @@ func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *a } func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { - if Bool(d.properties.Api_levels_annotations_enabled) { - d.apiVersionsXml = android.PathForModuleOut(ctx, "api-versions.xml") + if !Bool(d.properties.Api_levels_annotations_enabled) { + return + } - if len(d.properties.Api_levels_annotations_dirs) == 0 { - ctx.PropertyErrorf("api_levels_annotations_dirs", - "has to be non-empty if api levels annotations was enabled!") - } + d.apiVersionsXml = android.PathForModuleOut(ctx, "api-versions.xml") - cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml) - cmd.FlagWithInput("--apply-api-levels ", d.apiVersionsXml) - cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion()) - cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename()) - - ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) { - if t, ok := m.(*ExportedDroiddocDir); ok { - for _, dep := range t.deps { - if strings.HasSuffix(dep.String(), "android.jar") { - cmd.Implicit(dep) - } + if len(d.properties.Api_levels_annotations_dirs) == 0 { + ctx.PropertyErrorf("api_levels_annotations_dirs", + "has to be non-empty if api levels annotations was enabled!") + } + + cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml) + cmd.FlagWithInput("--apply-api-levels ", d.apiVersionsXml) + cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion()) + cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename()) + + filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar") + + ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) { + if t, ok := m.(*ExportedDroiddocDir); ok { + for _, dep := range t.deps { + if strings.HasSuffix(dep.String(), filename) { + cmd.Implicit(dep) } - cmd.FlagWithArg("--android-jar-pattern ", t.dir.String()+"/%/public/android.jar") - } else { - ctx.PropertyErrorf("api_levels_annotations_dirs", - "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m)) } - }) - - } + cmd.FlagWithArg("--android-jar-pattern ", t.dir.String()+"/%/public/"+filename) + } else { + ctx.PropertyErrorf("api_levels_annotations_dirs", + "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m)) + } + }) } func (d *Droidstubs) apiToXmlFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { - if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() && d.apiFile != nil { + if Bool(d.properties.Jdiff_enabled) && d.apiFile != nil { if d.apiFile.String() == "" { ctx.ModuleErrorf("API signature file has to be specified in Metalava when jdiff is enabled.") } @@ -1452,7 +1474,6 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi labels["shallow"] = "true" } 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, ",")...) } @@ -1504,7 +1525,9 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi cmd.Flag("--no-banner"). Flag("--color"). Flag("--quiet"). - Flag("--format=v2") + Flag("--format=v2"). + FlagWithArg("--repeat-errors-max ", "10"). + FlagWithArg("--hide ", "UnresolvedImport") return cmd } @@ -1545,14 +1568,14 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { d.apiLevelsAnnotationsFlags(ctx, cmd) d.apiToXmlFlags(ctx, cmd) - if strings.Contains(d.Javadoc.args, "--generate-documentation") { + if android.InList("--generate-documentation", d.Javadoc.args) { // Currently Metalava have the ability to invoke Javadoc in a seperate process. // Pass "-nodocs" to suppress the Javadoc invocation when Metalava receives // "--generate-documentation" arg. This is not needed when Metalava removes this feature. - d.Javadoc.args = d.Javadoc.args + " -nodocs " + d.Javadoc.args = append(d.Javadoc.args, "-nodocs") } - cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles) + cmd.Flag(strings.Join(d.Javadoc.args, " ")).Implicits(d.Javadoc.argFiles) for _, o := range d.Javadoc.properties.Out { cmd.ImplicitOutput(android.PathForModuleGen(ctx, o)) } @@ -1565,7 +1588,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Add API lint options. - if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) && !ctx.Config().IsPdkBuild() { + if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) { doApiLint = true newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since) @@ -1632,8 +1655,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Add "check released" options. (Detect incompatible API changes from the last public release) - if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") && - !ctx.Config().IsPdkBuild() { + if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") { doCheckReleased = true if len(d.Javadoc.properties.Out) > 0 { @@ -1666,7 +1688,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { impRule := android.NewRuleBuilder() impCmd := impRule.Command() - // A dummy action that copies the ninja generated rsp file to a new location. This allows us to + // An 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. @@ -1710,8 +1732,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { rule.Build(pctx, ctx, "metalava", "metalava merged") - if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") && - !ctx.Config().IsPdkBuild() { + if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") { if len(d.Javadoc.properties.Out) > 0 { ctx.PropertyErrorf("out", "out property may not be combined with check_api") @@ -1825,7 +1846,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { rule.Build(pctx, ctx, "nullabilityWarningsCheck", "nullability warnings check") } - if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() { + if Bool(d.properties.Jdiff_enabled) { if len(d.Javadoc.properties.Out) > 0 { ctx.PropertyErrorf("out", "out property may not be combined with jdiff") } diff --git a/java/hiddenapi.go b/java/hiddenapi.go index b5a021785..63b801a5c 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -23,8 +23,8 @@ import ( ) var hiddenAPIGenerateCSVRule = pctx.AndroidStaticRule("hiddenAPIGenerateCSV", blueprint.RuleParams{ - Command: "${config.Class2Greylist} --stub-api-flags ${stubAPIFlags} $in $outFlag $out", - CommandDeps: []string{"${config.Class2Greylist}"}, + Command: "${config.Class2NonSdkList} --stub-api-flags ${stubAPIFlags} $in $outFlag $out", + CommandDeps: []string{"${config.Class2NonSdkList}"}, }, "outFlag", "stubAPIFlags") type hiddenAPI struct { diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index 95dd0bb09..29b6bcd7d 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -43,7 +43,7 @@ func hiddenAPISingletonPaths(ctx android.PathContext) hiddenAPISingletonPathsStr return hiddenAPISingletonPathsStruct{ flags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-flags.csv"), index: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-index.csv"), - metadata: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-greylist.csv"), + metadata: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-unsupported.csv"), stubFlags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-stub-flags.txt"), } }).(hiddenAPISingletonPathsStruct) @@ -100,7 +100,7 @@ func stubFlagsRule(ctx android.SingletonContext) { // Add the android.test.base to the set of stubs only if the android.test.base module is on // the boot jars list as the runtime will only enforce hiddenapi access against modules on // that list. - if inList("android.test.base", ctx.Config().BootJars()) && !ctx.Config().UnbundledBuildUsePrebuiltSdks() { + if inList("android.test.base", ctx.Config().BootJars()) && !ctx.Config().AlwaysUsePrebuiltSdks() { publicStubModules = append(publicStubModules, "android.test.base.stubs") } @@ -116,7 +116,7 @@ func stubFlagsRule(ctx android.SingletonContext) { // Core Platform API stubs corePlatformStubModules := []string{ - "core.platform.api.stubs", + "legacy.core.platform.api.stubs", } // Allow products to define their own stubs for custom product jars that apps can use. @@ -147,7 +147,7 @@ func stubFlagsRule(ctx android.SingletonContext) { name := ctx.ModuleName(module) for moduleList, pathList := range moduleListToPathList { if i := android.IndexList(name, *moduleList); i != -1 { - pathList[i] = j.DexJar() + pathList[i] = j.DexJarBuildPath() } } } @@ -217,7 +217,7 @@ func moduleForGreyListRemovedApis(ctx android.SingletonContext, module android.M } // flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and -// the greylists. +// the unsupported API. func flagsRule(ctx android.SingletonContext) android.Path { var flagsCSV android.Paths var greylistRemovedApis android.Paths @@ -256,19 +256,19 @@ func flagsRule(ctx android.SingletonContext) android.Path { Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py")). FlagWithInput("--csv ", stubFlags). Inputs(flagsCSV). - FlagWithInput("--greylist ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist.txt")). - FlagWithInput("--greylist-ignore-conflicts ", combinedRemovedApis). - FlagWithInput("--greylist-max-q ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-q.txt")). - FlagWithInput("--greylist-max-p ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-p.txt")). - FlagWithInput("--greylist-max-o-ignore-conflicts ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-o.txt")). - FlagWithInput("--blacklist ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blacklist.txt")). - FlagWithInput("--greylist-packages ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-packages.txt")). + FlagWithInput("--unsupported ", + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-unsupported.txt")). + FlagWithInput("--unsupported-ignore-conflicts ", combinedRemovedApis). + FlagWithInput("--max-target-q ", + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-max-target-q.txt")). + FlagWithInput("--max-target-p ", + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-max-target-p.txt")). + FlagWithInput("--max-target-o-ignore-conflicts ", + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-max-target-o.txt")). + FlagWithInput("--blocked ", + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blocked.txt")). + FlagWithInput("--unsupported-packages ", + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-unsupported-packages.txt")). FlagWithOutput("--output ", tempPath) commitChangeForRestat(rule, tempPath, outputPath) @@ -293,7 +293,7 @@ func emptyFlagsRule(ctx android.SingletonContext) android.Path { return outputPath } -// metadataRule creates a rule to build hiddenapi-greylist.csv out of the metadata.csv files generated for boot image +// metadataRule creates a rule to build hiddenapi-unsupported.csv out of the metadata.csv files generated for boot image // modules. func metadataRule(ctx android.SingletonContext) android.Path { var metadataCSV android.Paths diff --git a/java/java.go b/java/java.go index 0a764e636..ecc2e2aaf 100644 --- a/java/java.go +++ b/java/java.go @@ -29,6 +29,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/dexpreopt" "android/soong/java/config" "android/soong/tradefed" ) @@ -44,7 +45,7 @@ func init() { PropertyName: "java_libs", }, func(j *Library) android.Path { - implementationJars := j.ImplementationJars() + implementationJars := j.ImplementationAndResourcesJars() if len(implementationJars) != 1 { panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name())) } @@ -140,10 +141,15 @@ func (j *Module) checkPlatformAPI(ctx android.ModuleContext) { // Findbugs type CompilerProperties struct { - // list of source files used to compile the Java module. May be .java, .logtags, .proto, + // list of source files used to compile the Java module. May be .java, .kt, .logtags, .proto, // or .aidl files. Srcs []string `android:"path,arch_variant"` + // list Kotlin of source files containing Kotlin code that should be treated as common code in + // a codebase that supports Kotlin multiplatform. See + // https://kotlinlang.org/docs/reference/multiplatform.html. May be only be .kt files. + Common_srcs []string `android:"path,arch_variant"` + // list of source files that should not be used to build the Java module. // This is most useful in the arch/multilib variants to remove non-common files Exclude_srcs []string `android:"path,arch_variant"` @@ -259,9 +265,6 @@ type CompilerProperties struct { } type CompilerDeviceProperties struct { - // list of module-specific flags that will be used for dex compiles - Dxflags []string `android:"arch_variant"` - // if not blank, set to the version of the sdk to compile against. // Defaults to compiling against the current platform. Sdk_version *string @@ -307,37 +310,6 @@ type CompilerDeviceProperties struct { } } - // If set to true, compile dex regardless of installable. Defaults to false. - Compile_dex *bool - - Optimize struct { - // If false, disable all optimization. Defaults to true for android_app and android_test - // modules, false for java_library and java_test modules. - Enabled *bool - // True if the module containing this has it set by default. - EnabledByDefault bool `blueprint:"mutated"` - - // If true, optimize for size by removing unused code. Defaults to true for apps, - // false for libraries and tests. - Shrink *bool - - // If true, optimize bytecode. Defaults to false. - Optimize *bool - - // If true, obfuscate bytecode. Defaults to false. - Obfuscate *bool - - // If true, do not use the flag files generated by aapt that automatically keep - // classes referenced by the app manifest. Defaults to false. - No_aapt_flags *bool - - // Flags to pass to proguard. - Proguard_flags []string - - // Specifies the locations of files containing proguard flags. - Proguard_flags_files []string `android:"path"` - } - // When targeting 1.9 and above, override the modules to use with --system, // otherwise provides defaults libraries to add to the bootclasspath. System_modules *string @@ -351,12 +323,6 @@ type CompilerDeviceProperties struct { // set the name of the output Stem *string - // 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"` // If true, generate the signature file of APK Signing Scheme V4, along side the signed APK file. @@ -364,10 +330,6 @@ type CompilerDeviceProperties struct { V4_signature *bool } -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 @@ -436,9 +398,6 @@ type Module struct { // output file containing uninstrumented classes that will be instrumented by jacoco jacocoReportClassesFile android.Path - // output file containing mapping of obfuscated names - proguardDictionary android.Path - // output file of the module, which may be a classes jar or a dex jar outputFile android.Path extraOutputFiles android.Paths @@ -454,14 +413,11 @@ type Module struct { compiledJavaSrcs android.Paths compiledSrcJars android.Paths - // list of extra progurad flag files - extraProguardFlagFiles android.Paths - // manifest file to use instead of properties.Manifest overrideManifest android.OptionalPath - // list of SDK lib names that this java module is exporting - exportedSdkLibs []string + // map of SDK libs exported by this java module to their build and install paths + exportedSdkLibs dexpreopt.LibraryPaths // list of plugins that this java module is exporting exportedPluginJars android.Paths @@ -483,13 +439,17 @@ type Module struct { extraResources android.Paths hiddenAPI + dexer dexpreopter linter // list of the xref extraction files kytheFiles android.Paths - distFile android.Path + distFiles android.TaggedDistFiles + + // Collect the module directory for IDE info in java/jdeps.go. + modulePaths []string } func (j *Module) addHostProperties() { @@ -503,6 +463,7 @@ func (j *Module) addHostAndDeviceProperties() { j.addHostProperties() j.AddProperties( &j.deviceProperties, + &j.dexer.dexProperties, &j.dexpreoptProperties, &j.linter.properties, ) @@ -515,7 +476,10 @@ func (j *Module) OutputFiles(tag string) (android.Paths, error) { case ".jar": return android.Paths{j.implementationAndResourcesJar}, nil case ".proguard_map": - return android.Paths{j.proguardDictionary}, nil + if j.dexer.proguardDictionary.Valid() { + return android.Paths{j.dexer.proguardDictionary.Path()}, nil + } + return nil, fmt.Errorf("%q was requested, but no output file was found.", tag) default: return nil, fmt.Errorf("unsupported module reference tag %q", tag) } @@ -529,13 +493,19 @@ type ApexDependency interface { ImplementationAndResourcesJars() android.Paths } +// Provides build path and install path to DEX jars. +type UsesLibraryDependency interface { + DexJarBuildPath() android.Path + DexJarInstallPath() android.Path +} + type Dependency interface { ApexDependency + UsesLibraryDependency ImplementationJars() android.Paths ResourceJars() android.Paths - DexJar() android.Path AidlIncludeDirs() android.Paths - ExportedSdkLibs() []string + ExportedSdkLibs() dexpreopt.LibraryPaths ExportedPlugins() (android.Paths, []string) SrcJarArgs() ([]string, android.Paths) BaseModuleName() string @@ -551,7 +521,20 @@ func (j *Module) XrefJavaFiles() android.Paths { } func InitJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) { - android.InitAndroidArchModule(module, hod, android.MultilibCommon) + initJavaModule(module, hod, false) +} + +func InitJavaModuleMultiTargets(module android.DefaultableModule, hod android.HostOrDeviceSupported) { + initJavaModule(module, hod, true) +} + +func initJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported, multiTargets bool) { + multilib := android.MultilibCommon + if multiTargets { + android.InitAndroidMultiTargetsArchModule(module, hod, multilib) + } else { + android.InitAndroidArchModule(module, hod, multilib) + } android.InitDefaultableModule(module) } @@ -570,6 +553,7 @@ func IsJniDepTag(depTag blueprint.DependencyTag) bool { } var ( + dataNativeBinsTag = dependencyTag{name: "dataNativeBins"} staticLibTag = dependencyTag{name: "staticlib"} libTag = dependencyTag{name: "javalib"} java9LibTag = dependencyTag{name: "java9lib"} @@ -578,7 +562,6 @@ var ( bootClasspathTag = dependencyTag{name: "bootclasspath"} systemModulesTag = dependencyTag{name: "system modules"} frameworkResTag = dependencyTag{name: "framework-res"} - frameworkApkTag = dependencyTag{name: "framework-apk"} kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib"} kotlinAnnotationsTag = dependencyTag{name: "kotlin-annotations"} proguardRaiseTag = dependencyTag{name: "proguard-raise"} @@ -597,7 +580,7 @@ func IsStaticLibDepTag(depTag blueprint.DependencyTag) bool { } type sdkDep struct { - useModule, useFiles, useDefaultLibs, invalidVersion bool + useModule, useFiles, invalidVersion bool // The modules that will be added to the bootclasspath when targeting 1.8 or lower bootclasspath []string @@ -606,7 +589,11 @@ type sdkDep struct { // modules are to be used. systemModules string + // The modules that will be added to the classpath regardless of the Java language level targeted + classpath []string + // The modules that will be added ot the classpath when targeting 1.9 or higher + // (normally these will be on the bootclasspath when targeting 1.8 or lower) java9Classpath []string frameworkResModule string @@ -645,6 +632,21 @@ func (j *Module) shouldInstrumentStatic(ctx android.BaseModuleContext) bool { ctx.Config().UnbundledBuild()) } +func (j *Module) shouldInstrumentInApex(ctx android.BaseModuleContext) bool { + // Force enable the instrumentation for java code that is built for APEXes ... + // except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent + // doesn't make sense) or framework libraries (e.g. libraries found in the InstrumentFrameworkModules list) unless EMMA_INSTRUMENT_FRAMEWORK is true. + isJacocoAgent := ctx.ModuleName() == "jacocoagent" + if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !isJacocoAgent && !j.IsForPlatform() { + if !inList(ctx.ModuleName(), config.InstrumentFrameworkModules) { + return true + } else if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") { + return true + } + } + return false +} + func (j *Module) sdkVersion() sdkSpec { return sdkSpecFrom(String(j.deviceProperties.Sdk_version)) } @@ -681,34 +683,29 @@ func (j *Module) AvailableFor(what string) bool { return j.ApexModuleBase.AvailableFor(what) } +func sdkDeps(ctx android.BottomUpMutatorContext, sdkContext sdkContext, d dexer) { + sdkDep := decodeSdkDep(ctx, sdkContext) + if sdkDep.useModule { + ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...) + ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...) + ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...) + if d.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() { + ctx.AddVariationDependencies(nil, proguardRaiseTag, config.LegacyCorePlatformBootclasspathLibraries...) + } + if d.effectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() { + ctx.AddVariationDependencies(nil, proguardRaiseTag, config.FrameworkLibraries...) + } + } + if sdkDep.systemModules != "" { + ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules) + } +} + func (j *Module) deps(ctx android.BottomUpMutatorContext) { if ctx.Device() { j.linter.deps(ctx) - sdkDep := decodeSdkDep(ctx, sdkContext(j)) - if sdkDep.useDefaultLibs { - ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...) - ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules) - if sdkDep.hasFrameworkLibs() { - ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...) - } - } else if sdkDep.useModule { - ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...) - 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" || - ctx.ModuleName() == "android_test_stubs_current" { - ctx.AddVariationDependencies(nil, frameworkApkTag, "framework-res") - } + sdkDeps(ctx, sdkContext(j), j.dexer) } syspropPublicStubs := syspropPublicStubs(ctx.Config()) @@ -875,8 +872,9 @@ type linkTypeContext interface { func (m *Module) getLinkType(name string) (ret linkType, stubs bool) { switch name { - case "core.current.stubs", "core.platform.api.stubs", "stub-annotations", - "private-stub-annotations-jar", "core-lambda-stubs", "core-generated-annotation-stubs": + case "core.current.stubs", "legacy.core.platform.api.stubs", "stable.core.platform.api.stubs", + "stub-annotations", "private-stub-annotations-jar", + "core-lambda-stubs", "core-generated-annotation-stubs": return javaCore, true case "android_stubs_current": return javaSdk, true @@ -982,12 +980,6 @@ 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) @@ -1007,7 +999,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, dep.OptionalImplicitSdkLibrary()...) + j.exportedSdkLibs.MaybeAddLibraryPath(ctx, dep.OptionalImplicitSdkLibrary(), dep.DexJarBuildPath(), dep.DexJarInstallPath()) case staticLibTag: ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName) } @@ -1018,7 +1010,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { case libTag, instrumentationForTag: deps.classpath = append(deps.classpath, dep.HeaderJars()...) // sdk lib names from dependencies are re-exported - j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...) + j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs()) deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...) pluginJars, pluginClasses := dep.ExportedPlugins() addPlugins(&deps, pluginJars, pluginClasses...) @@ -1030,7 +1022,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...) deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars()...) // sdk lib names from dependencies are re-exported - j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...) + j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs()) deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...) pluginJars, pluginClasses := dep.ExportedPlugins() addPlugins(&deps, pluginJars, pluginClasses...) @@ -1057,18 +1049,6 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } else { ctx.PropertyErrorf("exported_plugins", "%q is not a java_plugin module", otherName) } - case frameworkApkTag: - if ctx.ModuleName() == "android_stubs_current" || - ctx.ModuleName() == "android_system_stubs_current" || - ctx.ModuleName() == "android_test_stubs_current" { - // framework stubs.jar need to depend on framework-res.apk, in order to pull the - // resource files out of there for aapt. - // - // Normally the package rule runs aapt, which includes the resource, - // but we're not running that in our package rule so just copy in the - // resource files here. - deps.staticResourceJars = append(deps.staticResourceJars, dep.(*AndroidApp).exportPackage) - } case kotlinStdlibTag: deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars()...) case kotlinAnnotationsTag: @@ -1105,8 +1085,6 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } }) - j.exportedSdkLibs = android.FirstUniqueStrings(j.exportedSdkLibs) - return deps } @@ -1186,9 +1164,9 @@ func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaB if flags.javaVersion.usesJavaModules() { javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...) } - if ctx.Config().MinimizeJavaDebugInfo() { - // Override the -g flag passed globally to remove local variable debug info to reduce - // disk and memory usage. + if ctx.Config().MinimizeJavaDebugInfo() && !ctx.Host() { + // For non-host binaries, override the -g flag passed globally to remove + // local variable debug info to reduce disk and memory usage. javacFlags = append(javacFlags, "-g:source,lines") } javacFlags = append(javacFlags, "-Xlint:-dep-ann") @@ -1284,6 +1262,11 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { flags = protoFlags(ctx, &j.properties, &j.protoProperties, flags) } + kotlinCommonSrcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Common_srcs, nil) + if len(kotlinCommonSrcFiles.FilterOutByExt(".kt")) > 0 { + ctx.PropertyErrorf("common_srcs", "common_srcs must be .kt files") + } + srcFiles = j.genSources(ctx, srcFiles, flags) srcJars := srcFiles.FilterByExt(".srcjar") @@ -1337,6 +1320,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // Collect .kt files for AIDEGen j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, srcFiles.FilterByExt(".kt").Strings()...) + j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, kotlinCommonSrcFiles.Strings()...) flags.classpath = append(flags.classpath, deps.kotlinStdlib...) flags.classpath = append(flags.classpath, deps.kotlinAnnotations...) @@ -1348,7 +1332,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // Use kapt for annotation processing kaptSrcJar := android.PathForModuleOut(ctx, "kapt", "kapt-sources.jar") kaptResJar := android.PathForModuleOut(ctx, "kapt", "kapt-res.jar") - kotlinKapt(ctx, kaptSrcJar, kaptResJar, kotlinSrcFiles, srcJars, flags) + kotlinKapt(ctx, kaptSrcJar, kaptResJar, kotlinSrcFiles, kotlinCommonSrcFiles, srcJars, flags) srcJars = append(srcJars, kaptSrcJar) kotlinJars = append(kotlinJars, kaptResJar) // Disable annotation processing in javac, it's already been handled by kapt @@ -1357,7 +1341,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName) - kotlinCompile(ctx, kotlinJar, kotlinSrcFiles, srcJars, flags) + kotlinCompile(ctx, kotlinJar, kotlinSrcFiles, kotlinCommonSrcFiles, srcJars, flags) if ctx.Failed() { return } @@ -1583,11 +1567,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { j.headerJarFile = j.implementationJarFile } - // Force enable the instrumentation for java code that is built for APEXes ... - // except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent - // doesn't make sense) - isJacocoAgent := ctx.ModuleName() == "jacocoagent" - if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !isJacocoAgent && !j.IsForPlatform() { + if j.shouldInstrumentInApex(ctx) { j.properties.Instrument = true } @@ -1609,8 +1589,8 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // Enable dex compilation for the APEX variants, unless it is disabled explicitly if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !j.IsForPlatform() { - if j.deviceProperties.Compile_dex == nil { - j.deviceProperties.Compile_dex = proptools.BoolPtr(true) + if j.dexProperties.Compile_dex == nil { + j.dexProperties.Compile_dex = proptools.BoolPtr(true) } if j.deviceProperties.Hostdex == nil { j.deviceProperties.Hostdex = proptools.BoolPtr(true) @@ -1618,10 +1598,14 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } if ctx.Device() && j.hasCode(ctx) && - (Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) { + (Bool(j.properties.Installable) || Bool(j.dexProperties.Compile_dex)) { + if j.shouldInstrumentStatic(ctx) { + j.dexer.extraProguardFlagFiles = append(j.dexer.extraProguardFlagFiles, + android.PathForSource(ctx, "build/make/core/proguard.jacoco.flags")) + } // Dex compilation var dexOutputFile android.ModuleOutPath - dexOutputFile = j.compileDex(ctx, flags, outputFile, jarName) + dexOutputFile = j.dexer.compileDex(ctx, flags, j.minSdkVersion(), outputFile, jarName) if ctx.Failed() { return } @@ -1631,7 +1615,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // Hidden API CSV generation and dex encoding dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, j.implementationJarFile, - proptools.Bool(j.deviceProperties.Uncompress_dex)) + proptools.Bool(j.dexProperties.Uncompress_dex)) // merge dex jar with resources if necessary if j.resourceJar != nil { @@ -1639,7 +1623,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.Uncompress_dex { + if *j.dexProperties.Uncompress_dex { combinedAlignedJar := android.PathForModuleOut(ctx, "dex-withres-aligned", jarName) TransformZipAlign(ctx, combinedAlignedJar, combinedJar) dexOutputFile = combinedAlignedJar @@ -1683,6 +1667,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { j.linter.compileSdkVersion = lintSDKVersionString(j.sdkVersion()) j.linter.javaLanguageLevel = flags.javaVersion.String() j.linter.kotlinLanguageLevel = "1.3" + if j.ApexVariationName() != "" && ctx.Config().UnbundledBuildApps() { + j.linter.buildModuleReportZip = true + } j.linter.lint(ctx) } @@ -1811,10 +1798,14 @@ func (j *Module) ImplementationJars() android.Paths { return android.Paths{j.implementationJarFile} } -func (j *Module) DexJar() android.Path { +func (j *Module) DexJarBuildPath() android.Path { return j.dexJarFile } +func (j *Module) DexJarInstallPath() android.Path { + return j.installFile +} + func (j *Module) ResourceJars() android.Paths { if j.resourceJar == nil { return nil @@ -1834,8 +1825,7 @@ func (j *Module) AidlIncludeDirs() android.Paths { return j.exportAidlIncludeDirs } -func (j *Module) ExportedSdkLibs() []string { - // exportedSdkLibs is type []string +func (j *Module) ExportedSdkLibs() dexpreopt.LibraryPaths { return j.exportedSdkLibs } @@ -1862,6 +1852,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 { @@ -1880,6 +1871,24 @@ func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu return j.depIsInSameApex(ctx, dep) } +func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + sdkSpec := j.minSdkVersion() + if !sdkSpec.specified() { + return fmt.Errorf("min_sdk_version is not specified") + } + if sdkSpec.kind == sdkCore { + return nil + } + ver, err := sdkSpec.effectiveVersion(ctx) + if err != nil { + return err + } + if int(ver) > sdkVersion { + return fmt.Errorf("newer SDK(%v)", ver) + } + return nil +} + func (j *Module) Stem() string { return proptools.StringDefault(j.deviceProperties.Stem, j.Name()) } @@ -1900,18 +1909,9 @@ func (j *Module) IsInstallable() bool { // Java libraries (.jar file) // -type LibraryProperties struct { - Dist struct { - // The tag of the output of this module that should be output. - Tag *string `android:"arch_variant"` - } `android:"arch_variant"` -} - type Library struct { Module - libraryProperties LibraryProperties - InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths) } @@ -1953,13 +1953,17 @@ 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 - if j.deviceProperties.Uncompress_dex == nil { + if j.dexProperties.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.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter)) } - j.dexpreopter.uncompressedDex = *j.deviceProperties.Uncompress_dex + j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex + j.exportedSdkLibs = make(dexpreopt.LibraryPaths) 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 @@ -1970,14 +1974,13 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.Stem()+".jar", j.outputFile, extraInstallDeps...) } - // Verify Dist.Tag is set to a supported output - if j.libraryProperties.Dist.Tag != nil { - distFiles, err := j.OutputFiles(*j.libraryProperties.Dist.Tag) - if err != nil { - ctx.PropertyErrorf("dist.tag", "%s", err.Error()) - } - j.distFile = distFiles[0] - } + // 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.MaybeAddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), j.DexJarBuildPath(), j.DexJarInstallPath()) + + j.distFiles = j.GenerateTaggedDistFiles(ctx) } func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) { @@ -2095,7 +2098,6 @@ func LibraryFactory() android.Module { module := &Library{} module.addHostAndDeviceProperties() - module.AddProperties(&module.libraryProperties) module.initModuleAndImport(&module.ModuleBase) @@ -2130,6 +2132,12 @@ func LibraryHostFactory() android.Module { // Java Tests // +// Test option struct. +type TestOptions struct { + // a list of extra test configuration files that should be installed with the module. + Extra_test_configs []string `android:"path,arch_variant"` +} + type testProperties struct { // list of compatibility suites (for example "cts", "vts") that the module should be // installed into. @@ -2155,6 +2163,14 @@ type testProperties struct { // 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 + + // Test options. + Test_options TestOptions +} + +type hostTestProperties struct { + // list of native binary modules that should be installed alongside the test + Data_native_bins []string `android:"arch_variant"` } type testHelperLibraryProperties struct { @@ -2178,8 +2194,15 @@ type Test struct { testProperties testProperties - testConfig android.Path - data android.Paths + testConfig android.Path + extraTestConfigs android.Paths + data android.Paths +} + +type TestHost struct { + Test + + testHostProperties hostTestProperties } type TestHelperLibrary struct { @@ -2194,13 +2217,31 @@ type JavaTestImport struct { prebuiltTestProperties prebuiltTestProperties testConfig android.Path + dexJarFile android.Path +} + +func (j *TestHost) DepsMutator(ctx android.BottomUpMutatorContext) { + if len(j.testHostProperties.Data_native_bins) > 0 { + for _, target := range ctx.MultiTargets() { + ctx.AddVariationDependencies(target.Variations(), dataNativeBinsTag, j.testHostProperties.Data_native_bins...) + } + } + + j.deps(ctx) } func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template, j.testProperties.Test_suites, j.testProperties.Auto_gen_config) + j.data = android.PathsForModuleSrc(ctx, j.testProperties.Data) + j.extraTestConfigs = android.PathsForModuleSrc(ctx, j.testProperties.Test_options.Extra_test_configs) + + ctx.VisitDirectDepsWithTag(dataNativeBinsTag, func(dep android.Module) { + j.data = append(j.data, android.OutputFileForModule(ctx, dep, "")) + }) + j.Library.GenerateAndroidBuildActions(ctx) } @@ -2341,14 +2382,15 @@ func JavaTestImportFactory() android.Module { // A java_test_host has a single variant that produces a `.jar` file containing `.class` files that were // compiled against the host bootclasspath. func TestHostFactory() android.Module { - module := &Test{} + module := &TestHost{} module.addHostProperties() module.AddProperties(&module.testProperties) + module.AddProperties(&module.testHostProperties) module.Module.properties.Installable = proptools.BoolPtr(true) - InitJavaModule(module, android.HostSupported) + InitJavaModuleMultiTargets(module, android.HostSupported) return module } @@ -2480,6 +2522,12 @@ type ImportProperties struct { // set the name of the output Stem *string + + Aidl struct { + // directories that should be added as include directories for any aidl sources of modules + // that depend on this module, as well as to aidl for this module. + Export_include_dirs []string + } } type Import struct { @@ -2492,20 +2540,39 @@ type Import struct { // Functionality common to Module and Import. embeddableInModuleAndImport + hiddenAPI + dexer + properties ImportProperties + // output file containing classes.dex and resources + dexJarFile android.Path + combinedClasspathFile android.Path - exportedSdkLibs []string + exportedSdkLibs dexpreopt.LibraryPaths + exportAidlIncludeDirs android.Paths } func (j *Import) sdkVersion() sdkSpec { return sdkSpecFrom(String(j.properties.Sdk_version)) } +func (j *Import) makeSdkVersion() string { + return j.sdkVersion().raw +} + +func (j *Import) systemModules() string { + return "none" +} + func (j *Import) minSdkVersion() sdkSpec { return j.sdkVersion() } +func (j *Import) targetSdkVersion() sdkSpec { + return j.sdkVersion() +} + func (j *Import) MinSdkVersion() string { return j.minSdkVersion().version.String() } @@ -2532,6 +2599,10 @@ func (a *Import) JacocoReportClassesFile() android.Path { func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...) + + if ctx.Device() && Bool(j.dexProperties.Compile_dex) { + sdkDeps(ctx, sdkContext(j), j.dexer) + } } func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -2547,12 +2618,9 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { TransformJetifier(ctx, outputFile, inputFile) } j.combinedClasspathFile = outputFile + j.exportedSdkLibs = make(dexpreopt.LibraryPaths) - // 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()...) + var flags javaBuilderFlags ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) @@ -2562,23 +2630,55 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { case Dependency: switch tag { case libTag, staticLibTag: + flags.classpath = append(flags.classpath, dep.HeaderJars()...) // sdk lib names from dependencies are re-exported - j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...) + j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs()) + case bootClasspathTag: + flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars()...) } case SdkLibraryDependency: switch tag { case libTag: + flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) // names of sdk libs that are directly depended are exported - j.exportedSdkLibs = append(j.exportedSdkLibs, otherName) + j.exportedSdkLibs.AddLibraryPath(ctx, otherName, dep.DexJarBuildPath(), dep.DexJarInstallPath()) } } }) - j.exportedSdkLibs = android.FirstUniqueStrings(j.exportedSdkLibs) + var installFile android.Path if Bool(j.properties.Installable) { - ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), + installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), jarName, 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.MaybeAddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), outputFile, installFile) + + j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs) + + if ctx.Device() && Bool(j.dexProperties.Compile_dex) { + sdkDep := decodeSdkDep(ctx, sdkContext(j)) + if sdkDep.invalidVersion { + ctx.AddMissingDependencies(sdkDep.bootclasspath) + ctx.AddMissingDependencies(sdkDep.java9Classpath) + } else if sdkDep.useFiles { + // sdkDep.jar is actually equivalent to turbine header.jar. + flags.classpath = append(flags.classpath, sdkDep.jars...) + } + + // Dex compilation + var dexOutputFile android.ModuleOutPath + dexOutputFile = j.dexer.compileDex(ctx, flags, j.minSdkVersion(), outputFile, jarName) + if ctx.Failed() { + return + } + + j.dexJarFile = dexOutputFile + } } var _ Dependency = (*Import)(nil) @@ -2608,15 +2708,19 @@ func (j *Import) ImplementationAndResourcesJars() android.Paths { return android.Paths{j.combinedClasspathFile} } -func (j *Import) DexJar() android.Path { +func (j *Import) DexJarBuildPath() android.Path { + return j.dexJarFile +} + +func (j *Import) DexJarInstallPath() android.Path { return nil } func (j *Import) AidlIncludeDirs() android.Paths { - return nil + return j.exportAidlIncludeDirs } -func (j *Import) ExportedSdkLibs() []string { +func (j *Import) ExportedSdkLibs() dexpreopt.LibraryPaths { return j.exportedSdkLibs } @@ -2632,6 +2736,11 @@ func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu return j.depIsInSameApex(ctx, dep) } +func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + // Do not check for prebuilts against the min_sdk_version of enclosing APEX + return nil +} + // Add compile time check for interface implementation var _ android.IDEInfo = (*Import)(nil) var _ android.IDECustomizedModuleName = (*Import)(nil) @@ -2668,10 +2777,15 @@ var _ android.PrebuiltInterface = (*Import)(nil) func ImportFactory() android.Module { module := &Import{} - module.AddProperties(&module.properties) + module.AddProperties( + &module.properties, + &module.dexer.dexProperties, + ) module.initModuleAndImport(&module.ModuleBase) + module.dexProperties.Optimize.EnabledByDefault = false + android.InitPrebuiltModule(module, &module.properties.Jars) android.InitApexModule(module) android.InitSdkAwareModule(module) @@ -2738,6 +2852,10 @@ func (a *DexImport) JacocoReportClassesFile() android.Path { return nil } +func (a *DexImport) LintDepSets() LintDepSets { + return LintDepSets{} +} + func (j *DexImport) IsInstallable() bool { return true } @@ -2797,10 +2915,15 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { } } -func (j *DexImport) DexJar() android.Path { +func (j *DexImport) DexJarBuildPath() android.Path { return j.dexJarFile } +func (j *DexImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + // we don't check prebuilt modules for sdk_version + return nil +} + // dex_import imports a `.jar` file containing classes.dex files. // // A dex_import module cannot be used as a dependency of a java_* or android_* module, it can only be installed @@ -2866,6 +2989,7 @@ func DefaultsFactory() android.Module { module.AddProperties( &CompilerProperties{}, &CompilerDeviceProperties{}, + &DexProperties{}, &DexpreoptProperties{}, &android.ProtoProperties{}, &aaptProperties{}, @@ -2873,6 +2997,7 @@ func DefaultsFactory() android.Module { &appProperties{}, &appTestProperties{}, &overridableAppProperties{}, + &testProperties{}, &ImportProperties{}, &AARImportProperties{}, &sdkLibraryProperties{}, diff --git a/java/java_test.go b/java/java_test.go index f0de52fb9..3f7bab194 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -20,7 +20,6 @@ import ( "path/filepath" "reflect" "regexp" - "sort" "strconv" "strings" "testing" @@ -31,6 +30,7 @@ import ( "android/soong/cc" "android/soong/dexpreopt" "android/soong/genrule" + "android/soong/python" ) var buildDir string @@ -81,17 +81,22 @@ func testContext() *android.TestContext { ctx.RegisterModuleType("java_plugin", PluginFactory) ctx.RegisterModuleType("filegroup", android.FileGroupFactory) ctx.RegisterModuleType("genrule", genrule.GenRuleFactory) + ctx.RegisterModuleType("python_binary_host", python.PythonBinaryHostFactory) RegisterDocsBuildComponents(ctx) RegisterStubsBuildComponents(ctx) RegisterSdkLibraryBuildComponents(ctx) ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) + ctx.PreArchMutators(android.RegisterComponentsMutator) RegisterPrebuiltApisBuildComponents(ctx) + ctx.PreDepsMutators(python.RegisterPythonPreDepsMutators) ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators) ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory)) ctx.RegisterPreSingletonType("sdk_versions", android.SingletonFactoryAdaptor(sdkPreSingletonFactory)) + android.RegisterPrebuiltMutators(ctx) + // Register module types and mutators from cc needed for JNI testing cc.RegisterRequiredBuildComponentsForTest(ctx) @@ -466,7 +471,41 @@ func TestBinary(t *testing.T) { t.Errorf("expected binary wrapper implicits [%q], got %v", barJar, barWrapperDeps) } +} + +func TestHostBinaryNoJavaDebugInfoOverride(t *testing.T) { + bp := ` + java_library { + name: "target_library", + srcs: ["a.java"], + } + + java_binary_host { + name: "host_binary", + srcs: ["b.java"], + } + ` + config := testConfig(nil, bp, nil) + config.TestProductVariables.MinimizeJavaDebugInfo = proptools.BoolPtr(true) + + ctx, _ := testJavaWithConfig(t, config) + // first, check that the -g flag is added to target modules + targetLibrary := ctx.ModuleForTests("target_library", "android_common") + targetJavaFlags := targetLibrary.Module().VariablesForTests()["javacFlags"] + if !strings.Contains(targetJavaFlags, "-g:source,lines") { + t.Errorf("target library javac flags %v should contain "+ + "-g:source,lines override with MinimizeJavaDebugInfo", targetJavaFlags) + } + + // check that -g is not overridden for host modules + buildOS := android.BuildOs.String() + hostBinary := ctx.ModuleForTests("host_binary", buildOS+"_common") + hostJavaFlags := hostBinary.Module().VariablesForTests()["javacFlags"] + if strings.Contains(hostJavaFlags, "-g:source,lines") { + t.Errorf("java_binary_host javac flags %v should not have "+ + "-g:source,lines override with MinimizeJavaDebugInfo", hostJavaFlags) + } } func TestPrebuilts(t *testing.T) { @@ -486,6 +525,8 @@ func TestPrebuilts(t *testing.T) { java_import { name: "baz", jars: ["b.jar"], + sdk_version: "current", + compile_dex: true, } dex_import { @@ -516,8 +557,10 @@ func TestPrebuilts(t *testing.T) { fooModule := ctx.ModuleForTests("foo", "android_common") javac := fooModule.Rule("javac") combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac") - barJar := ctx.ModuleForTests("bar", "android_common").Rule("combineJar").Output - bazJar := ctx.ModuleForTests("baz", "android_common").Rule("combineJar").Output + barModule := ctx.ModuleForTests("bar", "android_common") + barJar := barModule.Rule("combineJar").Output + bazModule := ctx.ModuleForTests("baz", "android_common") + bazJar := bazModule.Rule("combineJar").Output sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").Rule("combineJar").Output fooLibrary := fooModule.Module().(*Library) @@ -532,6 +575,11 @@ func TestPrebuilts(t *testing.T) { t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barJar.String()) } + barDexJar := barModule.Module().(*Import).DexJarBuildPath() + if barDexJar != nil { + t.Errorf("bar dex jar build path expected to be nil, got %q", barDexJar) + } + if !strings.Contains(javac.Args["classpath"], sdklibStubsJar.String()) { t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String()) } @@ -540,6 +588,12 @@ func TestPrebuilts(t *testing.T) { t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, bazJar.String()) } + bazDexJar := bazModule.Module().(*Import).DexJarBuildPath().String() + expectedDexJar := buildDir + "/.intermediates/baz/android_common/dex/baz.jar" + if bazDexJar != expectedDexJar { + t.Errorf("baz dex jar build path expected %q, got %q", expectedDexJar, bazDexJar) + } + ctx.ModuleForTests("qux", "android_common").Rule("Cp") } @@ -596,6 +650,89 @@ func TestJavaSdkLibraryImport(t *testing.T) { t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String()) } } + + CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{ + `prebuilt_sdklib.stubs`, + `prebuilt_sdklib.stubs.source.test`, + `prebuilt_sdklib.stubs.system`, + `prebuilt_sdklib.stubs.test`, + }) +} + +func TestJavaSdkLibraryImport_WithSource(t *testing.T) { + ctx, _ := testJava(t, ` + java_sdk_library { + name: "sdklib", + srcs: ["a.java"], + sdk_version: "none", + system_modules: "none", + public: { + enabled: true, + }, + } + + java_sdk_library_import { + name: "sdklib", + public: { + jars: ["a.jar"], + }, + } + `) + + CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{ + `dex2oatd`, + `prebuilt_sdklib`, + `sdklib.impl`, + `sdklib.stubs`, + `sdklib.stubs.source`, + `sdklib.xml`, + }) + + CheckModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{ + `prebuilt_sdklib.stubs`, + `sdklib.impl`, + // This should be prebuilt_sdklib.stubs but is set to sdklib.stubs because the + // dependency is added after prebuilts may have been renamed and so has to use + // the renamed name. + `sdklib.xml`, + }) +} + +func TestJavaSdkLibraryImport_Preferred(t *testing.T) { + ctx, _ := testJava(t, ` + java_sdk_library { + name: "sdklib", + srcs: ["a.java"], + sdk_version: "none", + system_modules: "none", + public: { + enabled: true, + }, + } + + java_sdk_library_import { + name: "sdklib", + prefer: true, + public: { + jars: ["a.jar"], + }, + } + `) + + CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{ + `dex2oatd`, + `prebuilt_sdklib`, + `sdklib.impl`, + `sdklib.stubs`, + `sdklib.stubs.source`, + `sdklib.xml`, + }) + + CheckModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{ + `prebuilt_sdklib.stubs`, + `sdklib.impl`, + `sdklib.xml`, + }) } func TestDefaults(t *testing.T) { @@ -979,15 +1116,20 @@ func TestDroiddoc(t *testing.T) { ], proofread_file: "libcore-proofread.txt", todo_file: "libcore-docs-todo.html", - args: "-offlinemode -title \"libcore\"", + flags: ["-offlinemode -title \"libcore\""], } `, map[string][]byte{ "bar-doc/a.java": nil, "bar-doc/b.java": nil, }) + barDocModule := ctx.ModuleForTests("bar-doc", "android_common") + barDoc := barDocModule.Rule("javadoc") + notExpected := " -stubs " + if strings.Contains(barDoc.RuleParams.Command, notExpected) { + t.Errorf("bar-doc command contains flag %q to create stubs, but should not", notExpected) + } - barDoc := ctx.ModuleForTests("bar-doc", "android_common").Rule("javadoc") var javaSrcs []string for _, i := range barDoc.Inputs { javaSrcs = append(javaSrcs, i.Base()) @@ -996,7 +1138,7 @@ func TestDroiddoc(t *testing.T) { t.Errorf("inputs of bar-doc must be []string{\"a.java\"}, but was %#v.", javaSrcs) } - aidl := ctx.ModuleForTests("bar-doc", "android_common").Rule("aidl") + aidl := barDocModule.Rule("aidl") if g, w := barDoc.Implicits.Strings(), aidl.Output.String(); !inList(w, g) { t.Errorf("implicits of bar-doc must contain %q, but was %q.", w, g) } @@ -1006,6 +1148,98 @@ func TestDroiddoc(t *testing.T) { } } +func TestDroiddocArgsAndFlagsCausesError(t *testing.T) { + testJavaError(t, "flags is set. Cannot set args", ` + droiddoc_exported_dir { + name: "droiddoc-templates-sdk", + path: ".", + } + filegroup { + name: "bar-doc-aidl-srcs", + srcs: ["bar-doc/IBar.aidl"], + path: "bar-doc", + } + droiddoc { + name: "bar-doc", + srcs: [ + "bar-doc/a.java", + "bar-doc/IFoo.aidl", + ":bar-doc-aidl-srcs", + ], + exclude_srcs: [ + "bar-doc/b.java" + ], + custom_template: "droiddoc-templates-sdk", + hdf: [ + "android.whichdoc offline", + ], + knowntags: [ + "bar-doc/known_oj_tags.txt", + ], + proofread_file: "libcore-proofread.txt", + todo_file: "libcore-docs-todo.html", + flags: ["-offlinemode -title \"libcore\""], + args: "-offlinemode -title \"libcore\"", + } + `) +} + +func TestDroidstubs(t *testing.T) { + ctx, _ := testJavaWithFS(t, ` + droiddoc_exported_dir { + name: "droiddoc-templates-sdk", + path: ".", + } + + droidstubs { + name: "bar-stubs", + srcs: [ + "bar-doc/a.java", + ], + api_levels_annotations_dirs: [ + "droiddoc-templates-sdk", + ], + api_levels_annotations_enabled: true, + } + + droidstubs { + name: "bar-stubs-other", + srcs: [ + "bar-doc/a.java", + ], + api_levels_annotations_dirs: [ + "droiddoc-templates-sdk", + ], + api_levels_annotations_enabled: true, + api_levels_jar_filename: "android.other.jar", + } + `, + map[string][]byte{ + "bar-doc/a.java": nil, + }) + testcases := []struct { + moduleName string + expectedJarFilename string + }{ + { + moduleName: "bar-stubs", + expectedJarFilename: "android.jar", + }, + { + moduleName: "bar-stubs-other", + expectedJarFilename: "android.other.jar", + }, + } + for _, c := range testcases { + m := ctx.ModuleForTests(c.moduleName, "android_common") + metalava := m.Rule("metalava") + expected := "--android-jar-pattern ./%/public/" + c.expectedJarFilename + if actual := metalava.RuleParams.Command; !strings.Contains(actual, expected) { + t.Errorf("For %q, expected metalava argument %q, but was not found %q", c.moduleName, expected, actual) + } + } +} + func TestDroidstubsWithSystemModules(t *testing.T) { ctx, _ := testJava(t, ` droidstubs { @@ -1276,8 +1510,7 @@ func TestJavaSdkLibrary(t *testing.T) { // test if baz has exported SDK lib names foo and bar to qux qux := ctx.ModuleForTests("qux", "android_common") if quxLib, ok := qux.Module().(*Library); ok { - sdkLibs := quxLib.ExportedSdkLibs() - sort.Strings(sdkLibs) + sdkLibs := android.SortedStringKeys(quxLib.ExportedSdkLibs()) if w := []string{"bar", "foo", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) { t.Errorf("qux should export %q but exports %q", w, sdkLibs) } @@ -1345,6 +1578,28 @@ func TestJavaSdkLibrary_AccessOutputFiles_MissingScope(t *testing.T) { `) } +func TestJavaSdkLibrary_Deps(t *testing.T) { + ctx, _ := testJava(t, ` + java_sdk_library { + name: "sdklib", + srcs: ["a.java"], + sdk_version: "none", + system_modules: "none", + public: { + enabled: true, + }, + } + `) + + CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{ + `dex2oatd`, + `sdklib.impl`, + `sdklib.stubs`, + `sdklib.stubs.source`, + `sdklib.xml`, + }) +} + func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) { testJava(t, ` java_sdk_library_import { @@ -1808,3 +2063,52 @@ func checkBootClasspathForSystemModule(t *testing.T, ctx *android.TestContext, m t.Errorf("bootclasspath of %q must start with --system and end with %q, but was %#v.", moduleName, expectedSuffix, bootClasspath) } } + +func TestAidlExportIncludeDirsFromImports(t *testing.T) { + ctx, _ := testJava(t, ` + java_library { + name: "foo", + srcs: ["aidl/foo/IFoo.aidl"], + libs: ["bar"], + } + + java_import { + name: "bar", + jars: ["a.jar"], + aidl: { + export_include_dirs: ["aidl/bar"], + }, + } + `) + + aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command + expectedAidlFlag := "-Iaidl/bar" + if !strings.Contains(aidlCommand, expectedAidlFlag) { + t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag) + } +} + +func TestDataNativeBinaries(t *testing.T) { + ctx, config := testJava(t, ` + java_test_host { + name: "foo", + srcs: ["a.java"], + data_native_bins: ["bin"] + } + + python_binary_host { + name: "bin", + srcs: ["bin.py"], + } + `) + + buildOS := android.BuildOs.String() + + test := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost) + entries := android.AndroidMkEntriesForTest(t, config, "", test)[0] + expected := []string{buildDir + "/.intermediates/bin/" + buildOS + "_x86_64_PY3/bin:bin"} + actual := entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"] + if !reflect.DeepEqual(expected, actual) { + t.Errorf("Unexpected test data - expected: %q, actual: %q", expected, actual) + } +} diff --git a/java/jdeps.go b/java/jdeps.go index 4f636a59f..2b5ee7491 100644 --- a/java/jdeps.go +++ b/java/jdeps.go @@ -75,6 +75,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/kotlin.go b/java/kotlin.go index 673970b9c..e8c030aa7 100644 --- a/java/kotlin.go +++ b/java/kotlin.go @@ -31,7 +31,9 @@ var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports Command: `rm -rf "$classesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` + `mkdir -p "$classesDir" "$srcJarDir" "$emptyDir" && ` + `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` + - `${config.GenKotlinBuildFileCmd} $classpath "$name" $classesDir $out.rsp $srcJarDir/list > $kotlinBuildFile &&` + + `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` + + ` --out_dir "$classesDir" --srcs "$out.rsp" --srcs "$srcJarDir/list"` + + ` $commonSrcFilesArg --out "$kotlinBuildFile" && ` + `${config.KotlincCmd} ${config.JavacHeapFlags} $kotlincFlags ` + `-jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile -kotlin-home $emptyDir && ` + `${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir && ` + @@ -52,21 +54,43 @@ var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports Rspfile: "$out.rsp", RspfileContent: `$in`, }, - "kotlincFlags", "classpath", "srcJars", "srcJarDir", "classesDir", "kotlinJvmTarget", "kotlinBuildFile", - "emptyDir", "name") + "kotlincFlags", "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "classesDir", + "kotlinJvmTarget", "kotlinBuildFile", "emptyDir", "name") + +func kotlinCommonSrcsList(ctx android.ModuleContext, commonSrcFiles android.Paths) android.OptionalPath { + if len(commonSrcFiles) > 0 { + // The list of common_srcs may be too long to put on the command line, but + // we can't use the rsp file because it is already being used for srcs. + // Insert a second rule to write out the list of resources to a file. + commonSrcsList := android.PathForModuleOut(ctx, "kotlinc_common_srcs.list") + rule := android.NewRuleBuilder() + rule.Command().Text("cp").FlagWithRspFileInputList("", commonSrcFiles).Output(commonSrcsList) + rule.Build(pctx, ctx, "kotlin_common_srcs_list", "kotlin common_srcs list") + return android.OptionalPathForPath(commonSrcsList) + } + return android.OptionalPath{} +} // kotlinCompile takes .java and .kt sources and srcJars, and compiles the .kt sources into a classes jar in outputFile. func kotlinCompile(ctx android.ModuleContext, outputFile android.WritablePath, - srcFiles, srcJars android.Paths, + srcFiles, commonSrcFiles, srcJars android.Paths, flags javaBuilderFlags) { var deps android.Paths deps = append(deps, flags.kotlincClasspath...) deps = append(deps, srcJars...) + deps = append(deps, commonSrcFiles...) kotlinName := filepath.Join(ctx.ModuleDir(), ctx.ModuleSubDir(), ctx.ModuleName()) kotlinName = strings.ReplaceAll(kotlinName, "/", "__") + commonSrcsList := kotlinCommonSrcsList(ctx, commonSrcFiles) + commonSrcFilesArg := "" + if commonSrcsList.Valid() { + deps = append(deps, commonSrcsList.Path()) + commonSrcFilesArg = "--common_srcs " + commonSrcsList.String() + } + ctx.Build(pctx, android.BuildParams{ Rule: kotlinc, Description: "kotlinc", @@ -74,13 +98,14 @@ func kotlinCompile(ctx android.ModuleContext, outputFile android.WritablePath, Inputs: srcFiles, Implicits: deps, Args: map[string]string{ - "classpath": flags.kotlincClasspath.FormJavaClassPath("-classpath"), - "kotlincFlags": flags.kotlincFlags, - "srcJars": strings.Join(srcJars.Strings(), " "), - "classesDir": android.PathForModuleOut(ctx, "kotlinc", "classes").String(), - "srcJarDir": android.PathForModuleOut(ctx, "kotlinc", "srcJars").String(), - "kotlinBuildFile": android.PathForModuleOut(ctx, "kotlinc-build.xml").String(), - "emptyDir": android.PathForModuleOut(ctx, "kotlinc", "empty").String(), + "classpath": flags.kotlincClasspath.FormJavaClassPath(""), + "kotlincFlags": flags.kotlincFlags, + "commonSrcFilesArg": commonSrcFilesArg, + "srcJars": strings.Join(srcJars.Strings(), " "), + "classesDir": android.PathForModuleOut(ctx, "kotlinc", "classes").String(), + "srcJarDir": android.PathForModuleOut(ctx, "kotlinc", "srcJars").String(), + "kotlinBuildFile": android.PathForModuleOut(ctx, "kotlinc-build.xml").String(), + "emptyDir": android.PathForModuleOut(ctx, "kotlinc", "empty").String(), // http://b/69160377 kotlinc only supports -jvm-target 1.6 and 1.8 "kotlinJvmTarget": "1.8", "name": kotlinName, @@ -93,7 +118,9 @@ var kapt = pctx.AndroidRemoteStaticRule("kapt", android.RemoteRuleSupports{Goma: Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && ` + `mkdir -p "$srcJarDir" "$kaptDir/sources" "$kaptDir/classes" && ` + `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` + - `${config.GenKotlinBuildFileCmd} $classpath "$name" "" $out.rsp $srcJarDir/list > $kotlinBuildFile &&` + + `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` + + ` --srcs "$out.rsp" --srcs "$srcJarDir/list"` + + ` $commonSrcFilesArg --out "$kotlinBuildFile" && ` + `${config.KotlincCmd} ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} $kotlincFlags ` + `-Xplugin=${config.KotlinKaptJar} ` + `-P plugin:org.jetbrains.kotlin.kapt3:sources=$kaptDir/sources ` + @@ -120,21 +147,31 @@ var kapt = pctx.AndroidRemoteStaticRule("kapt", android.RemoteRuleSupports{Goma: RspfileContent: `$in`, }, "kotlincFlags", "encodedJavacFlags", "kaptProcessorPath", "kaptProcessor", - "classpath", "srcJars", "srcJarDir", "kaptDir", "kotlinJvmTarget", "kotlinBuildFile", "name", - "classesJarOut") + "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "kaptDir", "kotlinJvmTarget", + "kotlinBuildFile", "name", "classesJarOut") // kotlinKapt performs Kotlin-compatible annotation processing. It takes .kt and .java sources and srcjars, and runs // annotation processors over all of them, producing a srcjar of generated code in outputFile. The srcjar should be // added as an additional input to kotlinc and javac rules, and the javac rule should have annotation processing // disabled. func kotlinKapt(ctx android.ModuleContext, srcJarOutputFile, resJarOutputFile android.WritablePath, - srcFiles, srcJars android.Paths, + srcFiles, commonSrcFiles, srcJars android.Paths, flags javaBuilderFlags) { + srcFiles = append(android.Paths(nil), srcFiles...) + var deps android.Paths deps = append(deps, flags.kotlincClasspath...) deps = append(deps, srcJars...) deps = append(deps, flags.processorPath...) + deps = append(deps, commonSrcFiles...) + + commonSrcsList := kotlinCommonSrcsList(ctx, commonSrcFiles) + commonSrcFilesArg := "" + if commonSrcsList.Valid() { + deps = append(deps, commonSrcsList.Path()) + commonSrcFilesArg = "--common_srcs " + commonSrcsList.String() + } kaptProcessorPath := flags.processorPath.FormRepeatedClassPath("-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=") @@ -162,8 +199,9 @@ func kotlinKapt(ctx android.ModuleContext, srcJarOutputFile, resJarOutputFile an Inputs: srcFiles, Implicits: deps, Args: map[string]string{ - "classpath": flags.kotlincClasspath.FormJavaClassPath("-classpath"), + "classpath": flags.kotlincClasspath.FormJavaClassPath(""), "kotlincFlags": flags.kotlincFlags, + "commonSrcFilesArg": commonSrcFilesArg, "srcJars": strings.Join(srcJars.Strings(), " "), "srcJarDir": android.PathForModuleOut(ctx, "kapt", "srcJars").String(), "kotlinBuildFile": android.PathForModuleOut(ctx, "kapt", "build.xml").String(), diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go new file mode 100644 index 000000000..021920af6 --- /dev/null +++ b/java/legacy_core_platform_api_usage.go @@ -0,0 +1,174 @@ +// Copyright 2020 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package java + +import ( + "android/soong/android" + "android/soong/java/config" +) + +// This variable is effectively unused in pre-master branches, and is +// included (with the same value as it has in AOSP) only to ease +// merges between branches (see the comment in the +// useLegacyCorePlatformApi() function): +var legacyCorePlatformApiModules = []string{ + "ahat-test-dump", + "android.car", + "android.test.mock", + "android.test.mock.impl", + "AoapTestDeviceApp", + "AoapTestHostApp", + "api-stubs-docs", + "art_cts_jvmti_test_library", + "art-gtest-jars-MyClassNatives", + "BackupFrameworksServicesRoboTests", + "BandwidthEnforcementTest", + "BlockedNumberProvider", + "BluetoothInstrumentationTests", + "BluetoothMidiService", + "car-apps-common", + "CertInstaller", + "ConnectivityManagerTest", + "ContactsProvider", + "core-tests-support", + "CtsContentTestCases", + "CtsIkeTestCases", + "CtsLibcoreWycheproofBCTestCases", + "CtsMediaTestCases", + "CtsNetTestCases", + "CtsNetTestCasesLatestSdk", + "CtsSecurityTestCases", + "CtsUsageStatsTestCases", + "DisplayCutoutEmulationEmu01Overlay", + "DocumentsUIPerfTests", + "DocumentsUITests", + "DownloadProvider", + "DownloadProviderTests", + "DownloadProviderUi", + "DynamicSystemInstallationService", + "EmergencyInfo-lib", + "ethernet-service", + "EthernetServiceTests", + "ExternalStorageProvider", + "ExtServices", + "ExtServices-core", + "framework-all", + "framework-minus-apex", + "FrameworksCoreTests", + "FrameworksIkeTests", + "FrameworksNetCommonTests", + "FrameworksNetTests", + "FrameworksServicesRoboTests", + "FrameworksServicesTests", + "FrameworksUtilTests", + "hid", + "hidl_test_java_java", + "hwbinder", + "ims", + "KeyChain", + "ksoap2", + "LocalTransport", + "lockagent", + "mediaframeworktest", + "MediaProvider", + "MmsService", + "MtpDocumentsProvider", + "MultiDisplayProvider", + "NetworkStackIntegrationTestsLib", + "NetworkStackNextIntegrationTests", + "NetworkStackNextTests", + "NetworkStackTests", + "NetworkStackTestsLib", + "NfcNci", + "platform_library-docs", + "PrintSpooler", + "RollbackTest", + "services", + "services.accessibility", + "services.backup", + "services.core.unboosted", + "services.devicepolicy", + "services.print", + "services.usage", + "services.usb", + "Settings-core", + "SettingsLib", + "SettingsProvider", + "SettingsProviderTest", + "SettingsRoboTests", + "Shell", + "ShellTests", + "sl4a.Common", + "StatementService", + "SystemUI-core", + "SystemUISharedLib", + "SystemUI-tests", + "Telecom", + "TelecomUnitTests", + "telephony-common", + "TelephonyProvider", + "TelephonyProviderTests", + "TeleService", + "testables", + "TetheringTests", + "TetheringTestsLib", + "time_zone_distro_installer", + "time_zone_distro_installer-tests", + "time_zone_distro-tests", + "time_zone_updater", + "TvProvider", + "uiautomator-stubs-docs", + "UsbHostExternalManagementTestApp", + "UserDictionaryProvider", + "WallpaperBackup", + "wifi-service", +} + +// This variable is effectively unused in pre-master branches, and is +// included (with the same value as it has in AOSP) only to ease +// merges between branches (see the comment in the +// useLegacyCorePlatformApi() function): +var legacyCorePlatformApiLookup = make(map[string]struct{}) + +func init() { + for _, module := range legacyCorePlatformApiModules { + legacyCorePlatformApiLookup[module] = struct{}{} + } +} + +func useLegacyCorePlatformApi(ctx android.EarlyModuleContext) bool { + // In pre-master branches, we don't attempt to force usage of the stable + // version of the core/platform API. Instead, we always use the legacy + // version --- except in tests, where we always use stable, so that we + // can make the test assertions the same as other branches. + // This should be false in tests and true otherwise: + return ctx.Config().TestProductVariables == nil +} + +func corePlatformSystemModules(ctx android.EarlyModuleContext) string { + if useLegacyCorePlatformApi(ctx) { + return config.LegacyCorePlatformSystemModules + } else { + return config.StableCorePlatformSystemModules + } +} + +func corePlatformBootclasspathLibraries(ctx android.EarlyModuleContext) []string { + if useLegacyCorePlatformApi(ctx) { + return config.LegacyCorePlatformBootclasspathLibraries + } else { + return config.StableCorePlatformBootclasspathLibraries + } +} diff --git a/java/lint.go b/java/lint.go index 20a7dc49f..3a210cc0b 100644 --- a/java/lint.go +++ b/java/lint.go @@ -17,6 +17,7 @@ package java import ( "fmt" "sort" + "strings" "android/soong/android" ) @@ -68,28 +69,78 @@ type linter struct { outputs lintOutputs properties LintProperties + reports android.Paths + buildModuleReportZip bool } type lintOutputs struct { - html android.ModuleOutPath - text android.ModuleOutPath - xml android.ModuleOutPath - - transitiveHTML *android.DepSet - transitiveText *android.DepSet - transitiveXML *android.DepSet + html android.Path + text android.Path + xml android.Path - transitiveHTMLZip android.OptionalPath - transitiveTextZip android.OptionalPath - transitiveXMLZip android.OptionalPath + depSets LintDepSets } -type lintOutputIntf interface { +type lintOutputsIntf interface { lintOutputs() *lintOutputs } -var _ lintOutputIntf = (*linter)(nil) +type lintDepSetsIntf interface { + LintDepSets() LintDepSets +} + +type LintDepSets struct { + HTML, Text, XML *android.DepSet +} + +type LintDepSetsBuilder struct { + HTML, Text, XML *android.DepSetBuilder +} + +func NewLintDepSetBuilder() LintDepSetsBuilder { + return LintDepSetsBuilder{ + HTML: android.NewDepSetBuilder(android.POSTORDER), + Text: android.NewDepSetBuilder(android.POSTORDER), + XML: android.NewDepSetBuilder(android.POSTORDER), + } +} + +func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder { + l.HTML.Direct(html) + l.Text.Direct(text) + l.XML.Direct(xml) + return l +} + +func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder { + if depSets.HTML != nil { + l.HTML.Transitive(depSets.HTML) + } + if depSets.Text != nil { + l.Text.Transitive(depSets.Text) + } + if depSets.XML != nil { + l.XML.Transitive(depSets.XML) + } + return l +} + +func (l LintDepSetsBuilder) Build() LintDepSets { + return LintDepSets{ + HTML: l.HTML.Build(), + Text: l.Text.Build(), + XML: l.XML.Build(), + } +} + +func (l *linter) LintDepSets() LintDepSets { + return l.outputs.depSets +} + +var _ lintDepSetsIntf = (*linter)(nil) + +var _ lintOutputsIntf = (*linter)(nil) func (l *linter) lintOutputs() *lintOutputs { return &l.outputs @@ -104,7 +155,16 @@ func (l *linter) deps(ctx android.BottomUpMutatorContext) { return } - ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), extraLintCheckTag, l.properties.Lint.Extra_check_modules...) + extraCheckModules := l.properties.Lint.Extra_check_modules + + if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" { + if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" { + extraCheckModules = strings.Split(checkOnlyModules, ",") + } + } + + ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), + extraLintCheckTag, extraCheckModules...) } func (l *linter) writeLintProjectXML(ctx android.ModuleContext, @@ -192,7 +252,7 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, return projectXMLPath, configXMLPath, cacheDir, homeDir, deps } -// generateManifest adds a command to the rule to write a dummy manifest cat contains the +// generateManifest adds a command to the rule to write a simple manifest that contains the // minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest. func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.Path { manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml") @@ -237,16 +297,11 @@ func (l *linter) lint(ctx android.ModuleContext) { text := android.PathForModuleOut(ctx, "lint-report.txt") xml := android.PathForModuleOut(ctx, "lint-report.xml") - htmlDeps := android.NewDepSetBuilder(android.POSTORDER).Direct(html) - textDeps := android.NewDepSetBuilder(android.POSTORDER).Direct(text) - xmlDeps := android.NewDepSetBuilder(android.POSTORDER).Direct(xml) + depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml) ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) { - if depLint, ok := dep.(lintOutputIntf); ok { - depLintOutputs := depLint.lintOutputs() - htmlDeps.Transitive(depLintOutputs.transitiveHTML) - textDeps.Transitive(depLintOutputs.transitiveText) - xmlDeps.Transitive(depLintOutputs.transitiveXML) + if depLint, ok := dep.(lintDepSetsIntf); ok { + depSetsBuilder.Transitive(depLint.LintDepSets()) } }) @@ -254,7 +309,7 @@ func (l *linter) lint(ctx android.ModuleContext) { rule.Command().Text("mkdir -p").Flag(cacheDir.String()).Flag(homeDir.String()) var annotationsZipPath, apiVersionsXMLPath android.Path - if ctx.Config().UnbundledBuildUsePrebuiltSdks() { + if ctx.Config().AlwaysUsePrebuiltSdks() { annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip") apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml") } else { @@ -262,9 +317,9 @@ func (l *linter) lint(ctx android.ModuleContext) { apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx) } - rule.Command(). + cmd := rule.Command(). Text("("). - Flag("JAVA_OPTS=-Xmx2048m"). + Flag("JAVA_OPTS=-Xmx3072m"). FlagWithArg("ANDROID_SDK_HOME=", homeDir.String()). FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath). FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath). @@ -282,9 +337,13 @@ func (l *linter) lint(ctx android.ModuleContext) { FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())). Flag("--exitcode"). Flags(l.properties.Lint.Flags). - Implicits(deps). - Text("|| (").Text("cat").Input(text).Text("; exit 7)"). - Text(")") + Implicits(deps) + + if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" { + cmd.FlagWithArg("--check ", checkOnly) + } + + cmd.Text("|| (").Text("cat").Input(text).Text("; exit 7)").Text(")") rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String()) @@ -295,24 +354,33 @@ func (l *linter) lint(ctx android.ModuleContext) { text: text, xml: xml, - transitiveHTML: htmlDeps.Build(), - transitiveText: textDeps.Build(), - transitiveXML: xmlDeps.Build(), + depSets: depSetsBuilder.Build(), } if l.buildModuleReportZip { - htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip") - l.outputs.transitiveHTMLZip = android.OptionalPathForPath(htmlZip) - lintZip(ctx, l.outputs.transitiveHTML.ToSortedList(), htmlZip) + l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets()) + } +} - textZip := android.PathForModuleOut(ctx, "lint-report-text.zip") - l.outputs.transitiveTextZip = android.OptionalPathForPath(textZip) - lintZip(ctx, l.outputs.transitiveText.ToSortedList(), textZip) +func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths { + htmlList := depSets.HTML.ToSortedList() + textList := depSets.Text.ToSortedList() + xmlList := depSets.XML.ToSortedList() - xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip") - l.outputs.transitiveXMLZip = android.OptionalPathForPath(xmlZip) - lintZip(ctx, l.outputs.transitiveXML.ToSortedList(), xmlZip) + if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 { + return nil } + + htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip") + lintZip(ctx, htmlList, htmlZip) + + textZip := android.PathForModuleOut(ctx, "lint-report-text.zip") + lintZip(ctx, textList, textZip) + + xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip") + lintZip(ctx, xmlList, xmlZip) + + return android.Paths{htmlZip, textZip, xmlZip} } type lintSingleton struct { @@ -327,7 +395,7 @@ func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) { } func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) { - if ctx.Config().UnbundledBuildUsePrebuiltSdks() { + if ctx.Config().AlwaysUsePrebuiltSdks() { return } @@ -389,7 +457,7 @@ func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) { return } - if l, ok := m.(lintOutputIntf); ok { + if l, ok := m.(lintOutputsIntf); ok { outputs = append(outputs, l.lintOutputs()) } }) @@ -400,7 +468,9 @@ func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) { var paths android.Paths for _, output := range outputs { - paths = append(paths, get(output)) + if p := get(output); p != nil { + paths = append(paths, p) + } } lintZip(ctx, paths, outputPath) @@ -443,7 +513,7 @@ func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android rule.Command().BuiltTool(ctx, "soong_zip"). FlagWithOutput("-o ", outputPath). FlagWithArg("-C ", android.PathForIntermediates(ctx).String()). - FlagWithRspFileInputList("-l ", paths) + FlagWithRspFileInputList("-r ", paths) rule.Build(pctx, ctx, outputPath.Base(), outputPath.Base()) } diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go index 999c72f3c..ac8337dc5 100644 --- a/java/prebuilt_apis.go +++ b/java/prebuilt_apis.go @@ -34,6 +34,10 @@ func RegisterPrebuiltApisBuildComponents(ctx android.RegistrationContext) { type prebuiltApisProperties struct { // list of api version directories Api_dirs []string + + // The sdk_version of java_import modules generated based on jar files. + // Defaults to "current" + Imports_sdk_version *string } type prebuiltApis struct { @@ -74,7 +78,7 @@ func prebuiltApiModuleName(mctx android.LoadHookContext, module string, scope st return mctx.ModuleName() + "_" + scope + "_" + apiver + "_" + module } -func createImport(mctx android.LoadHookContext, module string, scope string, apiver string, path string) { +func createImport(mctx android.LoadHookContext, module, scope, apiver, path, sdk_version string) { props := struct { Name *string Jars []string @@ -83,8 +87,7 @@ func createImport(mctx android.LoadHookContext, module string, scope string, api }{} 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") + props.Sdk_version = proptools.StringPtr(sdk_version) props.Installable = proptools.BoolPtr(false) mctx.CreateModule(ImportFactory, &props) @@ -101,10 +104,10 @@ func createFilegroup(mctx android.LoadHookContext, module string, scope string, mctx.CreateModule(android.FileGroupFactory, &filegroupProps) } -func getPrebuiltFiles(mctx android.LoadHookContext, name string) []string { +func getPrebuiltFiles(mctx android.LoadHookContext, p *prebuiltApis, name string) []string { mydir := mctx.ModuleDir() + "/" var files []string - for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs { + for _, apiver := range p.properties.Api_dirs { for _, scope := range []string{"public", "system", "test", "core", "module-lib", "system-server"} { vfiles, err := mctx.GlobWithDeps(mydir+apiver+"/"+scope+"/"+name, nil) if err != nil { @@ -116,16 +119,18 @@ func getPrebuiltFiles(mctx android.LoadHookContext, name string) []string { return files } -func prebuiltSdkStubs(mctx android.LoadHookContext) { +func prebuiltSdkStubs(mctx android.LoadHookContext, p *prebuiltApis) { mydir := mctx.ModuleDir() + "/" // <apiver>/<scope>/<module>.jar - files := getPrebuiltFiles(mctx, "*.jar") + files := getPrebuiltFiles(mctx, p, "*.jar") + + sdk_version := proptools.StringDefault(p.properties.Imports_sdk_version, "current") for _, f := range files { // create a Import module for each jar file localPath := strings.TrimPrefix(f, mydir) module, apiver, scope := parseJarPath(localPath) - createImport(mctx, module, scope, apiver, localPath) + createImport(mctx, module, scope, apiver, localPath, sdk_version) } } @@ -140,8 +145,8 @@ func createSystemModules(mctx android.LoadHookContext, apiver string) { mctx.CreateModule(SystemModulesFactory, &props) } -func prebuiltSdkSystemModules(mctx android.LoadHookContext) { - for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs { +func prebuiltSdkSystemModules(mctx android.LoadHookContext, p *prebuiltApis) { + for _, apiver := range p.properties.Api_dirs { jar := android.ExistentPathForSource(mctx, mctx.ModuleDir(), apiver, "public", "core-for-system-modules.jar") if jar.Valid() { @@ -150,10 +155,10 @@ func prebuiltSdkSystemModules(mctx android.LoadHookContext) { } } -func prebuiltApiFiles(mctx android.LoadHookContext) { +func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) { mydir := mctx.ModuleDir() + "/" // <apiver>/<scope>/api/<module>.txt - files := getPrebuiltFiles(mctx, "api/*.txt") + files := getPrebuiltFiles(mctx, p, "api/*.txt") if len(files) == 0 { mctx.ModuleErrorf("no api file found under %q", mydir) @@ -201,10 +206,10 @@ func prebuiltApiFiles(mctx android.LoadHookContext) { } func createPrebuiltApiModules(mctx android.LoadHookContext) { - if _, ok := mctx.Module().(*prebuiltApis); ok { - prebuiltApiFiles(mctx) - prebuiltSdkStubs(mctx) - prebuiltSdkSystemModules(mctx) + if p, ok := mctx.Module().(*prebuiltApis); ok { + prebuiltApiFiles(mctx, p) + prebuiltSdkStubs(mctx, p) + prebuiltSdkSystemModules(mctx, p) } } diff --git a/java/robolectric.go b/java/robolectric.go index c6b07a17e..3fe6626bb 100644 --- a/java/robolectric.go +++ b/java/robolectric.go @@ -21,10 +21,13 @@ import ( "strings" "android/soong/android" + "android/soong/java/config" + "android/soong/tradefed" ) func init() { android.RegisterModuleType("android_robolectric_test", RobolectricTestFactory) + android.RegisterModuleType("android_robolectric_runtimes", robolectricRuntimesFactory) } var robolectricDefaultLibs = []string{ @@ -32,10 +35,13 @@ var robolectricDefaultLibs = []string{ "Robolectric_all-target", "mockito-robolectric-prebuilt", "truth-prebuilt", + // TODO(ccross): this is not needed at link time + "junitxml", } var ( - roboCoverageLibsTag = dependencyTag{name: "roboSrcs"} + roboCoverageLibsTag = dependencyTag{name: "roboCoverageLibs"} + roboRuntimesTag = dependencyTag{name: "roboRuntimes"} ) type robolectricProperties struct { @@ -58,13 +64,28 @@ type robolectricTest struct { Library robolectricProperties robolectricProperties + testProperties testProperties libs []string tests []string + manifest android.Path + resourceApk android.Path + + combinedJar android.WritablePath + roboSrcJar android.Path + + testConfig android.Path + data android.Paths +} + +func (r *robolectricTest) TestSuites() []string { + return r.testProperties.Test_suites } +var _ android.TestSuiteModule = (*robolectricTest)(nil) + func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) { r.Library.DepsMutator(ctx) @@ -77,9 +98,16 @@ func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...) ctx.AddVariationDependencies(nil, roboCoverageLibsTag, r.robolectricProperties.Coverage_libs...) + + ctx.AddVariationDependencies(nil, roboRuntimesTag, "robolectric-android-all-prebuilts") } func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { + r.testConfig = tradefed.AutoGenRobolectricTestConfig(ctx, r.testProperties.Test_config, + r.testProperties.Test_config_template, r.testProperties.Test_suites, + r.testProperties.Auto_gen_config) + r.data = android.PathsForModuleSrc(ctx, r.testProperties.Data) + roboTestConfig := android.PathForModuleGen(ctx, "robolectric"). Join(ctx, "com/android/tools/test_config.properties") @@ -95,6 +123,9 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) ctx.PropertyErrorf("instrumentation_for", "dependency must be an android_app") } + r.manifest = instrumentedApp.mergedManifestFile + r.resourceApk = instrumentedApp.outputFile + generateRoboTestConfig(ctx, roboTestConfig, instrumentedApp) r.extraResources = android.Paths{roboTestConfig} @@ -104,10 +135,30 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) r.generateRoboSrcJar(ctx, roboSrcJar, instrumentedApp) r.roboSrcJar = roboSrcJar + roboTestConfigJar := android.PathForModuleOut(ctx, "robolectric_samedir", "samedir_config.jar") + generateSameDirRoboTestConfigJar(ctx, roboTestConfigJar) + + combinedJarJars := android.Paths{ + // roboTestConfigJar comes first so that its com/android/tools/test_config.properties + // overrides the one from r.extraResources. The r.extraResources one can be removed + // once the Make test runner is removed. + roboTestConfigJar, + r.outputFile, + instrumentedApp.implementationAndResourcesJar, + } + for _, dep := range ctx.GetDirectDepsWithTag(libTag) { - r.libs = append(r.libs, dep.(Dependency).BaseModuleName()) + m := dep.(Dependency) + r.libs = append(r.libs, m.BaseModuleName()) + if !android.InList(m.BaseModuleName(), config.FrameworkLibraries) { + combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars()...) + } } + r.combinedJar = android.PathForModuleOut(ctx, "robolectric_combined", r.outputFile.Base()) + TransformJarsToJar(ctx, r.combinedJar, "combine jars", combinedJarJars, android.OptionalPath{}, + false, nil, nil) + // TODO: this could all be removed if tradefed was used as the test runner, it will find everything // annotated as a test and run it. for _, src := range r.compiledJavaSrcs { @@ -121,14 +172,38 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) } r.tests = append(r.tests, s) } + + r.data = append(r.data, r.manifest, r.resourceApk) + + runtimes := ctx.GetDirectDepWithTag("robolectric-android-all-prebuilts", roboRuntimesTag) + + installPath := android.PathForModuleInstall(ctx, r.BaseModuleName()) + + installedResourceApk := ctx.InstallFile(installPath, ctx.ModuleName()+".apk", r.resourceApk) + installedManifest := ctx.InstallFile(installPath, ctx.ModuleName()+"-AndroidManifest.xml", r.manifest) + installedConfig := ctx.InstallFile(installPath, ctx.ModuleName()+".config", r.testConfig) + + var installDeps android.Paths + for _, runtime := range runtimes.(*robolectricRuntimes).runtimes { + installDeps = append(installDeps, runtime) + } + installDeps = append(installDeps, installedResourceApk, installedManifest, installedConfig) + + for _, data := range android.PathsForModuleSrc(ctx, r.testProperties.Data) { + installedData := ctx.InstallFile(installPath, data.Rel(), data) + installDeps = append(installDeps, installedData) + } + + ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...) } -func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath, instrumentedApp *AndroidApp) { +func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath, + instrumentedApp *AndroidApp) { + rule := android.NewRuleBuilder() + manifest := instrumentedApp.mergedManifestFile resourceApk := instrumentedApp.outputFile - rule := android.NewRuleBuilder() - rule.Command().Text("rm -f").Output(outputFile) rule.Command(). Textf(`echo "android_merged_manifest=%s" >>`, manifest.String()).Output(outputFile).Text("&&"). @@ -141,6 +216,28 @@ func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.Writab rule.Build(pctx, ctx, "generate_test_config", "generate test_config.properties") } +func generateSameDirRoboTestConfigJar(ctx android.ModuleContext, outputFile android.ModuleOutPath) { + rule := android.NewRuleBuilder() + + outputDir := outputFile.InSameDir(ctx) + configFile := outputDir.Join(ctx, "com/android/tools/test_config.properties") + rule.Temporary(configFile) + rule.Command().Text("rm -f").Output(outputFile).Output(configFile) + rule.Command().Textf("mkdir -p $(dirname %s)", configFile.String()) + rule.Command(). + Text("("). + Textf(`echo "android_merged_manifest=%s-AndroidManifest.xml" &&`, ctx.ModuleName()). + Textf(`echo "android_resource_apk=%s.apk"`, ctx.ModuleName()). + Text(") >>").Output(configFile) + rule.Command(). + BuiltTool(ctx, "soong_zip"). + FlagWithArg("-C ", outputDir.String()). + FlagWithInput("-f ", configFile). + FlagWithOutput("-o ", outputFile) + + rule.Build(pctx, ctx, "generate_test_config_samedir", "generate test_config.properties") +} + func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFile android.WritablePath, instrumentedApp *AndroidApp) { @@ -202,7 +299,6 @@ func (r *robolectricTest) writeTestRunner(w io.Writer, module, name string, test fmt.Fprintln(w, "LOCAL_ROBOTEST_TIMEOUT :=", *t) } fmt.Fprintln(w, "-include external/robolectric-shadows/run_robotests.mk") - } // An android_robolectric_test module compiles tests against the Robolectric framework that can run on the local host @@ -218,11 +314,82 @@ func RobolectricTestFactory() android.Module { module.addHostProperties() module.AddProperties( &module.Module.deviceProperties, - &module.robolectricProperties) + &module.robolectricProperties, + &module.testProperties) module.Module.dexpreopter.isTest = true module.Module.linter.test = true + module.testProperties.Test_suites = []string{"robolectric-tests"} + InitJavaModule(module, android.DeviceSupported) return module } + +func (r *robolectricTest) InstallBypassMake() bool { return true } +func (r *robolectricTest) InstallInTestcases() bool { return true } +func (r *robolectricTest) InstallForceOS() *android.OsType { return &android.BuildOs } + +func robolectricRuntimesFactory() android.Module { + module := &robolectricRuntimes{} + module.AddProperties(&module.props) + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + return module +} + +type robolectricRuntimesProperties struct { + Jars []string `android:"path"` + Lib *string +} + +type robolectricRuntimes struct { + android.ModuleBase + + props robolectricRuntimesProperties + + runtimes []android.InstallPath +} + +func (r *robolectricRuntimes) TestSuites() []string { + return []string{"robolectric-tests"} +} + +var _ android.TestSuiteModule = (*robolectricRuntimes)(nil) + +func (r *robolectricRuntimes) DepsMutator(ctx android.BottomUpMutatorContext) { + if !ctx.Config().AlwaysUsePrebuiltSdks() && r.props.Lib != nil { + ctx.AddVariationDependencies(nil, libTag, String(r.props.Lib)) + } +} + +func (r *robolectricRuntimes) GenerateAndroidBuildActions(ctx android.ModuleContext) { + files := android.PathsForModuleSrc(ctx, r.props.Jars) + + androidAllDir := android.PathForModuleInstall(ctx, "android-all") + for _, from := range files { + installedRuntime := ctx.InstallFile(androidAllDir, from.Base(), from) + r.runtimes = append(r.runtimes, installedRuntime) + } + + if !ctx.Config().AlwaysUsePrebuiltSdks() && r.props.Lib != nil { + runtimeFromSourceModule := ctx.GetDirectDepWithTag(String(r.props.Lib), libTag) + if runtimeFromSourceModule == nil { + if ctx.Config().AllowMissingDependencies() { + ctx.AddMissingDependencies([]string{String(r.props.Lib)}) + } else { + ctx.PropertyErrorf("lib", "missing dependency %q", String(r.props.Lib)) + } + return + } + runtimeFromSourceJar := android.OutputFileForModule(ctx, runtimeFromSourceModule, "") + + runtimeName := fmt.Sprintf("android-all-%s-robolectric-r0.jar", + ctx.Config().PlatformSdkCodename()) + installedRuntime := ctx.InstallFile(androidAllDir, runtimeName, runtimeFromSourceJar) + r.runtimes = append(r.runtimes, installedRuntime) + } +} + +func (r *robolectricRuntimes) InstallBypassMake() bool { return true } +func (r *robolectricRuntimes) InstallInTestcases() bool { return true } +func (r *robolectricRuntimes) InstallForceOS() *android.OsType { return &android.BuildOs } diff --git a/java/sdk.go b/java/sdk.go index f96ecded4..56fa12b3e 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -53,7 +53,7 @@ type sdkContext interface { func UseApiFingerprint(ctx android.BaseModuleContext) bool { if ctx.Config().UnbundledBuild() && - !ctx.Config().UnbundledBuildUsePrebuiltSdks() && + !ctx.Config().AlwaysUsePrebuiltSdks() && ctx.Config().IsEnvTrue("UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT") { return true } @@ -94,9 +94,9 @@ func (k sdkKind) String() string { case sdkCorePlatform: return "core_platform" case sdkModule: - return "module" + return "module-lib" case sdkSystemServer: - return "system_server" + return "system-server" default: return "invalid" } @@ -191,19 +191,22 @@ func (s sdkSpec) prebuiltSdkAvailableForUnbundledBuild() bool { return s.kind != sdkPrivate && s.kind != sdkNone && s.kind != sdkCorePlatform } -// forPdkBuild converts this sdkSpec into another sdkSpec that is for the PDK builds. -func (s sdkSpec) forPdkBuild(ctx android.EarlyModuleContext) sdkSpec { - // For PDK builds, use the latest SDK version instead of "current" or "" - if s.kind == sdkPrivate || s.kind == sdkPublic { - kind := s.kind - if kind == sdkPrivate { - // We don't have prebuilt SDK for private APIs, so use the public SDK - // instead. This looks odd, but that's how it has been done. - // TODO(b/148271073): investigate the need for this. - kind = sdkPublic +func (s sdkSpec) forVendorPartition(ctx android.EarlyModuleContext) sdkSpec { + // If BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES has a numeric value, + // use it instead of "current" for the vendor partition. + currentSdkVersion := ctx.DeviceConfig().CurrentApiLevelForVendorModules() + if currentSdkVersion == "current" { + return s + } + + if s.kind == sdkPublic || s.kind == sdkSystem { + if s.version.isCurrent() { + if i, err := strconv.Atoi(currentSdkVersion); err == nil { + version := sdkVersion(i) + return sdkSpec{s.kind, version, s.raw} + } + panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion)) } - version := sdkVersion(LatestSdkVersionInt(ctx)) - return sdkSpec{kind, version, s.raw} } return s } @@ -212,9 +215,9 @@ func (s sdkSpec) forPdkBuild(ctx android.EarlyModuleContext) sdkSpec { func (s sdkSpec) usePrebuilt(ctx android.EarlyModuleContext) bool { if s.version.isCurrent() { // "current" can be built from source and be from prebuilt SDK - return ctx.Config().UnbundledBuildUsePrebuiltSdks() + return ctx.Config().AlwaysUsePrebuiltSdks() } else if s.version.isNumbered() { - // sanity check + // validation check if s.kind != sdkPublic && s.kind != sdkSystem && s.kind != sdkTest { panic(fmt.Errorf("prebuilt SDK is not not available for sdkKind=%q", s.kind)) return false @@ -233,8 +236,9 @@ func (s sdkSpec) effectiveVersion(ctx android.EarlyModuleContext) (sdkVersion, e if !s.valid() { return s.version, fmt.Errorf("invalid sdk version %q", s.raw) } - if ctx.Config().IsPdkBuild() { - s = s.forPdkBuild(ctx) + + if ctx.DeviceSpecific() || ctx.SocSpecific() { + s = s.forVendorPartition(ctx) } if s.version.isNumbered() { return s.version, nil @@ -321,6 +325,28 @@ func sdkSpecFrom(str string) sdkSpec { } } +func (s sdkSpec) validateSystemSdk(ctx android.EarlyModuleContext) bool { + // Ensures that the specified system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor/product Java module) + // Assuming that BOARD_SYSTEMSDK_VERSIONS := 28 29, + // sdk_version of the modules in vendor/product that use system sdk must be either system_28, system_29 or system_current + if s.kind != sdkSystem || !s.version.isNumbered() { + return true + } + allowedVersions := ctx.DeviceConfig().PlatformSystemSdkVersions() + if ctx.DeviceSpecific() || ctx.SocSpecific() || (ctx.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) { + systemSdkVersions := ctx.DeviceConfig().SystemSdkVersions() + if len(systemSdkVersions) > 0 { + allowedVersions = systemSdkVersions + } + } + if len(allowedVersions) > 0 && !android.InList(s.version.String(), allowedVersions) { + ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q", + s.raw, allowedVersions) + return false + } + return true +} + func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep { sdkVersion := sdkContext.sdkVersion() if !sdkVersion.valid() { @@ -328,8 +354,12 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep return sdkDep{} } - if ctx.Config().IsPdkBuild() { - sdkVersion = sdkVersion.forPdkBuild(ctx) + if ctx.DeviceSpecific() || ctx.SocSpecific() { + sdkVersion = sdkVersion.forVendorPartition(ctx) + } + + if !sdkVersion.validateSystemSdk(ctx) { + return sdkDep{} } if sdkVersion.usePrebuilt(ctx) { @@ -384,25 +414,13 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep } } - // Ensures that the specificed system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor apks) - // or PRODUCT_SYSTEMSDK_VERSIONS (for other apks or when BOARD_SYSTEMSDK_VERSIONS is not set) - if sdkVersion.kind == sdkSystem && sdkVersion.version.isNumbered() { - allowed_versions := ctx.DeviceConfig().PlatformSystemSdkVersions() - if ctx.DeviceSpecific() || ctx.SocSpecific() { - if len(ctx.DeviceConfig().SystemSdkVersions()) > 0 { - allowed_versions = ctx.DeviceConfig().SystemSdkVersions() - } - } - if len(allowed_versions) > 0 && !android.InList(sdkVersion.version.String(), allowed_versions) { - ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q", - sdkVersion.raw, allowed_versions) - } - } - switch sdkVersion.kind { case sdkPrivate: return sdkDep{ - useDefaultLibs: true, + useModule: true, + systemModules: corePlatformSystemModules(ctx), + bootclasspath: corePlatformBootclasspathLibraries(ctx), + classpath: config.FrameworkLibraries, frameworkResModule: "framework-res", } case sdkNone: @@ -424,9 +442,10 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep } case sdkCorePlatform: return sdkDep{ - useDefaultLibs: true, - frameworkResModule: "framework-res", - noFrameworksLibs: true, + useModule: true, + systemModules: corePlatformSystemModules(ctx), + bootclasspath: corePlatformBootclasspathLibraries(ctx), + noFrameworksLibs: true, } case sdkPublic: return toModule([]string{"android_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx)) @@ -435,7 +454,12 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep case sdkTest: return toModule([]string{"android_test_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx)) case sdkCore: - return toModule([]string{"core.current.stubs"}, "", nil) + return sdkDep{ + useModule: true, + bootclasspath: []string{"core.current.stubs", config.DefaultLambdaStubsLibrary}, + systemModules: "core-current-stubs-system-modules", + noFrameworksLibs: true, + } case sdkModule: // TODO(146757305): provide .apk and .aidl that have more APIs for modules return toModule([]string{"android_module_lib_stubs_current"}, "framework-res", nonUpdatableFrameworkAidlPath(ctx)) @@ -492,7 +516,7 @@ func sdkSingletonFactory() android.Singleton { type sdkSingleton struct{} func (sdkSingleton) GenerateBuildActions(ctx android.SingletonContext) { - if ctx.Config().UnbundledBuildUsePrebuiltSdks() || ctx.Config().IsPdkBuild() { + if ctx.Config().AlwaysUsePrebuiltSdks() { return } @@ -612,10 +636,7 @@ func createAPIFingerprint(ctx android.SingletonContext) { if ctx.Config().PlatformSdkCodename() == "REL" { cmd.Text("echo REL >").Output(out) - } else if ctx.Config().IsPdkBuild() { - // TODO: get this from the PDK artifacts? - cmd.Text("echo PDK >").Output(out) - } else if !ctx.Config().UnbundledBuildUsePrebuiltSdks() { + } else if !ctx.Config().AlwaysUsePrebuiltSdks() { in, err := ctx.GlobWithDeps("frameworks/base/api/*current.txt", nil) if err != nil { ctx.Errorf("error globbing API files: %s", err) @@ -644,7 +665,7 @@ func ApiFingerprintPath(ctx android.PathContext) android.OutputPath { } func sdkMakeVars(ctx android.MakeVarsContext) { - if ctx.Config().UnbundledBuildUsePrebuiltSdks() || ctx.Config().IsPdkBuild() { + if ctx.Config().AlwaysUsePrebuiltSdks() { return } diff --git a/java/sdk_library.go b/java/sdk_library.go index 679c07597..88cf46826 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -70,6 +70,12 @@ func (tag scopeDependencyTag) extractDepInfo(ctx android.ModuleContext, dep andr } } +var _ android.ReplaceSourceWithPrebuilt = (*scopeDependencyTag)(nil) + +func (tag scopeDependencyTag) ReplaceSourceWithPrebuilt() bool { + return false +} + // Provides information about an api scope, e.g. public, system, test. type apiScope struct { // The name of the api scope, e.g. public, system, test @@ -120,24 +126,23 @@ type apiScope struct { // the prebuilt jar. sdkVersion string - // Extra arguments to pass to droidstubs for this scope. - droidstubsArgs []string + // The annotation that identifies this API level, empty for the public API scope. + annotation string - // The args that must be passed to droidstubs to generate the stubs source - // for this scope. + // Extra arguments to pass to droidstubs 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 + // This is not used directly but is used to construct the droidstubsArgs. + extraArgs []string - // The args that must be passed to droidstubs to generate the API for this scope. + // The args that must be passed to droidstubs to generate the API and stubs source + // for this scope, constructed dynamically by initApiScope(). // // 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 + // + // The stubs source must include the definitions of everything that is in this + // api scope and all the scopes that this one extends. + droidstubsArgs []string // Whether the api scope can be treated as unstable, and should skip compat checks. unstable bool @@ -174,21 +179,23 @@ func initApiScope(scope *apiScope) *apiScope { // 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...) + var scopeSpecificArgs []string + if scope.annotation != "" { + scopeSpecificArgs = []string{"--show-annotation", scope.annotation} } - scope.droidstubsArgsForGeneratingStubsSource = stubsSourceArgs + for s := scope; s != nil; s = s.extends { + scopeSpecificArgs = append(scopeSpecificArgs, s.extraArgs...) - // 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 + // Ensure that the generated stubs includes all the API elements from the API scope + // that this scope extends. + if s != scope && s.annotation != "" { + scopeSpecificArgs = append(scopeSpecificArgs, "--show-for-stub-purposes-annotation", s.annotation) + } + } - // 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) + // Escape any special characters in the arguments. This is needed because droidstubs + // passes these directly to the shell command. + scope.droidstubsArgs = proptools.ShellEscapeList(scopeSpecificArgs) return scope } @@ -243,10 +250,10 @@ var ( scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties { return &module.sdkLibraryProperties.System }, - apiFilePrefix: "system-", - moduleSuffix: ".system", - sdkVersion: "system_current", - droidstubsArgs: []string{"-showAnnotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)"}, + apiFilePrefix: "system-", + moduleSuffix: ".system", + sdkVersion: "system_current", + annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS)", }) apiScopeTest = initApiScope(&apiScope{ name: "test", @@ -255,11 +262,11 @@ var ( scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties { return &module.sdkLibraryProperties.Test }, - apiFilePrefix: "test-", - moduleSuffix: ".test", - sdkVersion: "test_current", - droidstubsArgs: []string{"-showAnnotation android.annotation.TestApi"}, - unstable: true, + apiFilePrefix: "test-", + moduleSuffix: ".test", + sdkVersion: "test_current", + annotation: "android.annotation.TestApi", + unstable: true, }) apiScopeModuleLib = initApiScope(&apiScope{ name: "module-lib", @@ -276,9 +283,7 @@ var ( apiFilePrefix: "module-lib-", moduleSuffix: ".module_lib", sdkVersion: "module_current", - droidstubsArgs: []string{ - "--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\)", - }, + annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES)", }) apiScopeSystemServer = initApiScope(&apiScope{ name: "system-server", @@ -295,11 +300,11 @@ var ( apiFilePrefix: "system-server-", moduleSuffix: ".system_server", sdkVersion: "system_server_current", - droidstubsArgs: []string{ - "--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\) ", - "--hide-annotation android.annotation.Hide", + annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.SYSTEM_SERVER)", + extraArgs: []string{ + "--hide-annotation", "android.annotation.Hide", // com.android.* classes are okay in this interface" - "--hide InternalClasses", + "--hide", "InternalClasses", }, }) allApiScopes = apiScopes{ @@ -847,22 +852,20 @@ func (e *EmbeddableSdkLibraryComponent) initSdkLibraryComponent(moduleBase *andr } // to satisfy SdkLibraryComponentDependency -func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() []string { - if e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack != nil { - return []string{*e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack} - } - return nil +func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() *string { + return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack } // 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 { + UsesLibraryDependency + // 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 + // Returns the name of the optional implicit SDK library or nil, if there isn't one. + OptionalImplicitSdkLibrary() *string } // Make sure that all the module types that are components of java_sdk_library/_import @@ -976,21 +979,14 @@ func IsXmlPermissionsFileDepTag(depTag blueprint.DependencyTag) bool { var implLibraryTag = sdkLibraryComponentTag{name: "impl-library"} -func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { +// Add the dependencies on the child modules in the component deps mutator. +func (module *SdkLibrary) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { for _, apiScope := range module.getGeneratedApiScopes(ctx) { // Add dependencies to the stubs library ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(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)) - } + // 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)) } if module.requiresRuntimeImplementationLibrary() { @@ -1001,7 +997,12 @@ func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { // Add dependency to the rule for generating the xml permissions file ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlPermissionsModuleName()) } + } +} +// Add other dependencies as normal. +func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { + if module.requiresRuntimeImplementationLibrary() { // Only add the deps for the library if it is actually going to be built. module.Library.deps(ctx) } @@ -1045,8 +1046,10 @@ func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries { return nil } entriesList := module.Library.AndroidMkEntries() - entries := &entriesList[0] - entries.Required = append(entries.Required, module.xmlPermissionsModuleName()) + if module.sharedLibrary() { + entries := &entriesList[0] + entries.Required = append(entries.Required, module.xmlPermissionsModuleName()) + } return entriesList } @@ -1086,11 +1089,25 @@ func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope *apiScope) stri return ":" + module.BaseModuleName() + "-removed.api." + apiScope.name + ".latest" } +func childModuleVisibility(childVisibility []string) []string { + if childVisibility == nil { + // No child visibility set. The child will use the visibility of the sdk_library. + return nil + } + + // Prepend an override to ignore the sdk_library's visibility, and rely on the child visibility. + var visibility []string + visibility = append(visibility, "//visibility:override") + visibility = append(visibility, childVisibility...) + return visibility +} + // Creates the implementation java library func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) { - moduleNamePtr := proptools.StringPtr(module.BaseModuleName()) + visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility) + props := struct { Name *string Visibility []string @@ -1098,7 +1115,7 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) ConfigurationName *string }{ Name: proptools.StringPtr(module.implLibraryModuleName()), - Visibility: module.sdkLibraryProperties.Impl_library_visibility, + Visibility: visibility, // Set the instrument property to ensure it is instrumented when instrumentation is required. Instrument: true, @@ -1110,6 +1127,7 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) &module.properties, &module.protoProperties, &module.deviceProperties, + &module.dexProperties, &module.dexpreoptProperties, &module.linter.properties, &props, @@ -1121,22 +1139,17 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) // 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 - Compile_dex *bool - Java_version *string - Product_variables struct { - Pdk struct { - Enabled *bool - } - } - Openjdk9 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 + Openjdk9 struct { Srcs []string Javacflags []string } @@ -1149,12 +1162,7 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext }{} 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. - visibility := module.sdkLibraryProperties.Stubs_library_visibility - props.Visibility = visibility - + props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility) // sources are generated from the droiddoc props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)} sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope) @@ -1168,14 +1176,13 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext if proptools.Bool(module.sdkLibraryProperties.Annotations_enabled) { props.Libs = append(props.Libs, "stub-annotations") } - props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false) props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags // We compile the stubs for 1.8 in line with the main android.jar stubs, and potential // interop with older developer tools that don't support 1.9. props.Java_version = proptools.StringPtr("1.8") - if module.deviceProperties.Compile_dex != nil { - props.Compile_dex = module.deviceProperties.Compile_dex + if module.dexProperties.Compile_dex != nil { + props.Compile_dex = module.dexProperties.Compile_dex } // Dist the class jar artifact for sdk builds. @@ -1191,7 +1198,7 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext // 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, name string, createStubSources, createApi bool, scopeSpecificDroidstubsArgs []string) { +func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, scopeSpecificDroidstubsArgs []string) { props := struct { Name *string Visibility []string @@ -1236,12 +1243,7 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC // * libs (static_libs/libs) 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.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_source_visibility) props.Srcs = append(props.Srcs, module.properties.Srcs...) props.Sdk_version = module.deviceProperties.Sdk_version props.System_modules = module.deviceProperties.System_modules @@ -1280,64 +1282,57 @@ 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, scopeSpecificDroidstubsArgs...) props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " ")) - 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) - } + // 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) @@ -1393,22 +1388,22 @@ func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s sdkSpec) and return android.Paths{jarPath.Path()} } -// Get the apex name for module, "" if it is for platform. -func getApexNameForModule(module android.Module) string { +// Get the apex names for module, nil if it is for platform. +func getApexNamesForModule(module android.Module) []string { if apex, ok := module.(android.ApexModule); ok { - return apex.ApexName() + return apex.InApexes() } - return "" + return nil } -// Check to see if the other module is within the same named APEX as this module. +// Check to see if the other module is within the same set of named APEXes as this module. // // If either this or the other module are on the platform then this will return // false. -func withinSameApexAs(module android.ApexModule, other android.Module) bool { - name := module.ApexName() - return name != "" && getApexNameForModule(other) == name +func withinSameApexesAs(module android.ApexModule, other android.Module) bool { + names := module.InApexes() + return len(names) > 0 && reflect.DeepEqual(names, getApexNamesForModule(other)) } func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths { @@ -1427,7 +1422,7 @@ func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkS // 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 || withinSameApexAs(module, ctx.Module()) { + if sdkVersion.kind == sdkPrivate || withinSameApexesAs(module, ctx.Module()) { if headerJars { return module.HeaderJars() } else { @@ -1520,22 +1515,8 @@ 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) - } + // Use the stubs source name for legacy reasons. + module.createStubsSourcesAndApi(mctx, scope, module.stubsSourceModuleName(scope), scope.droidstubsArgs) module.createStubsLibrary(mctx, scope) } @@ -1824,7 +1805,7 @@ func (module *SdkLibraryImport) Name() string { func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHookContext) { // If the build is configured to use prebuilts then force this to be preferred. - if mctx.Config().UnbundledBuildUsePrebuiltSdks() { + if mctx.Config().AlwaysUsePrebuiltSdks() { module.prebuilt.ForcePrefer() } @@ -1882,20 +1863,26 @@ func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.Defaulta props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer()) } -func (module *SdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) { +// Add the dependencies on the child module in the component deps mutator so that it +// creates references to the prebuilt and not the source modules. +func (module *SdkLibraryImport) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { for apiScope, scopeProperties := range module.scopeProperties { if len(scopeProperties.Jars) == 0 { continue } // Add dependencies to the prebuilt stubs library - ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope)) + ctx.AddVariationDependencies(nil, apiScope.stubsTag, "prebuilt_"+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)) + ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, "prebuilt_"+module.stubsSourceModuleName(apiScope)) } } +} + +// Add other dependencies as normal. +func (module *SdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) { implName := module.implLibraryModuleName() if ctx.OtherModuleExists(implName) { @@ -1920,6 +1907,11 @@ func (module *SdkLibraryImport) DepIsInSameApex(mctx android.BaseModuleContext, return false } +func (module *SdkLibraryImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + // we don't check prebuilt modules for sdk_version + return nil +} + func (module *SdkLibraryImport) OutputFiles(tag string) (android.Paths, error) { return module.commonOutputFiles(tag) } @@ -1969,7 +1961,7 @@ func (module *SdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersio // For consistency with SdkLibrary make the implementation jar available to libraries that // are within the same APEX. implLibraryModule := module.implLibraryModule - if implLibraryModule != nil && withinSameApexAs(module, ctx.Module()) { + if implLibraryModule != nil && withinSameApexesAs(module, ctx.Module()) { if headerJars { return implLibraryModule.HeaderJars() } else { @@ -1992,12 +1984,21 @@ func (module *SdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleCont return module.sdkJars(ctx, sdkVersion, false) } -// to satisfy apex.javaDependency interface -func (module *SdkLibraryImport) DexJar() android.Path { +// to satisfy SdkLibraryDependency interface +func (module *SdkLibraryImport) DexJarBuildPath() android.Path { + if module.implLibraryModule == nil { + return nil + } else { + return module.implLibraryModule.DexJarBuildPath() + } +} + +// to satisfy SdkLibraryDependency interface +func (module *SdkLibraryImport) DexJarInstallPath() android.Path { if module.implLibraryModule == nil { return nil } else { - return module.implLibraryModule.DexJar() + return module.implLibraryModule.DexJarInstallPath() } } @@ -2011,6 +2012,15 @@ func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path { } // to satisfy apex.javaDependency interface +func (module *SdkLibraryImport) LintDepSets() LintDepSets { + if module.implLibraryModule == nil { + return LintDepSets{} + } else { + return module.implLibraryModule.LintDepSets() + } +} + +// to satisfy apex.javaDependency interface func (module *SdkLibraryImport) Stem() string { return module.BaseModuleName() } @@ -2067,6 +2077,17 @@ func sdkLibraryXmlFactory() android.Module { return module } +func (module *sdkLibraryXml) UniqueApexVariations() bool { + // sdkLibraryXml needs a unique variation per APEX because the generated XML file contains the path to the + // mounted APEX, which contains the name of the APEX. + return true +} + +// from android.PrebuiltEtcModule +func (module *sdkLibraryXml) BaseDir() string { + return "etc" +} + // from android.PrebuiltEtcModule func (module *sdkLibraryXml) SubDir() string { return "permissions" @@ -2086,11 +2107,16 @@ func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) { // do nothing } +func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + // sdkLibraryXml doesn't need to be checked separately because java_sdk_library is checked + return nil +} + // File path to the runtime implementation library func (module *sdkLibraryXml) implPath() string { implName := proptools.String(module.properties.Lib_name) - if apexName := module.ApexName(); apexName != "" { - // TODO(b/146468504): ApexName() is only a soong module name, not apex name. + if apexName := module.ApexVariationName(); apexName != "" { + // TODO(b/146468504): ApexVariationName() is only a soong module name, not apex name. // In most cases, this works fine. But when apex_name is set or override_apex is used // this can be wrong. return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexName, implName) diff --git a/java/sdk_test.go b/java/sdk_test.go index 52d2df552..776069dc9 100644 --- a/java/sdk_test.go +++ b/java/sdk_test.go @@ -30,7 +30,6 @@ func TestClasspath(t *testing.T) { var classpathTestcases = []struct { name string unbundled bool - pdk bool moduleType string host android.OsClass properties string @@ -49,27 +48,27 @@ func TestClasspath(t *testing.T) { }{ { name: "default", - bootclasspath: config.DefaultBootclasspathLibraries, - system: config.DefaultSystemModules, - java8classpath: config.DefaultLibraries, - java9classpath: config.DefaultLibraries, + bootclasspath: config.StableCorePlatformBootclasspathLibraries, + system: config.StableCorePlatformSystemModules, + java8classpath: config.FrameworkLibraries, + java9classpath: config.FrameworkLibraries, aidl: "-Iframework/aidl", }, { name: `sdk_version:"core_platform"`, properties: `sdk_version:"core_platform"`, - bootclasspath: config.DefaultBootclasspathLibraries, - system: config.DefaultSystemModules, + bootclasspath: config.StableCorePlatformBootclasspathLibraries, + system: config.StableCorePlatformSystemModules, java8classpath: []string{}, aidl: "", }, { name: "blank sdk version", properties: `sdk_version: "",`, - bootclasspath: config.DefaultBootclasspathLibraries, - system: config.DefaultSystemModules, - java8classpath: config.DefaultLibraries, - java9classpath: config.DefaultLibraries, + bootclasspath: config.StableCorePlatformBootclasspathLibraries, + system: config.StableCorePlatformSystemModules, + java8classpath: config.FrameworkLibraries, + java9classpath: config.FrameworkLibraries, aidl: "-Iframework/aidl", }, { @@ -139,11 +138,10 @@ func TestClasspath(t *testing.T) { }, { - name: "core_current", - properties: `sdk_version: "core_current",`, - bootclasspath: []string{"core.current.stubs", "core-lambda-stubs"}, - system: "core-current-stubs-system-modules", - java9classpath: []string{"core.current.stubs"}, + name: "core_current", + properties: `sdk_version: "core_current",`, + bootclasspath: []string{"core.current.stubs", "core-lambda-stubs"}, + system: "core-current-stubs-system-modules", }, { @@ -156,9 +154,9 @@ func TestClasspath(t *testing.T) { { name: "nostdlib system_modules", - properties: `sdk_version: "none", system_modules: "core-platform-api-stubs-system-modules"`, - system: "core-platform-api-stubs-system-modules", - bootclasspath: []string{"core-platform-api-stubs-system-modules-lib"}, + properties: `sdk_version: "none", system_modules: "stable-core-platform-api-stubs-system-modules"`, + system: "stable-core-platform-api-stubs-system-modules", + bootclasspath: []string{"stable-core-platform-api-stubs-system-modules-lib"}, java8classpath: []string{}, }, { @@ -218,35 +216,6 @@ func TestClasspath(t *testing.T) { }, { - name: "pdk default", - pdk: true, - 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: "pdk current", - pdk: true, - properties: `sdk_version: "current",`, - 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: "pdk 29", - pdk: true, - properties: `sdk_version: "29",`, - 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: "module_current", properties: `sdk_version: "module_current",`, bootclasspath: []string{"android_module_lib_stubs_current", "core-lambda-stubs"}, @@ -385,9 +354,7 @@ func TestClasspath(t *testing.T) { config := testConfig(nil, bpJava8, nil) if testcase.unbundled { config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true) - } - if testcase.pdk { - config.TestProductVariables.Pdk = proptools.BoolPtr(true) + config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(true) } ctx := testContext() run(t, ctx, config) @@ -408,9 +375,7 @@ func TestClasspath(t *testing.T) { config := testConfig(nil, bp, nil) if testcase.unbundled { config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true) - } - if testcase.pdk { - config.TestProductVariables.Pdk = proptools.BoolPtr(true) + config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(true) } ctx := testContext() run(t, ctx, config) @@ -434,9 +399,7 @@ func TestClasspath(t *testing.T) { if testcase.unbundled { config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true) - } - if testcase.pdk { - config.TestProductVariables.Pdk = proptools.BoolPtr(true) + config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(true) } ctx := testContext() run(t, ctx, config) @@ -452,9 +415,7 @@ func TestClasspath(t *testing.T) { if testcase.unbundled { config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true) - } - if testcase.pdk { - config.TestProductVariables.Pdk = proptools.BoolPtr(true) + config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(true) } ctx := testContext() run(t, ctx, config) diff --git a/java/testing.go b/java/testing.go index 48e449f34..70c857f39 100644 --- a/java/testing.go +++ b/java/testing.go @@ -16,9 +16,15 @@ package java import ( "fmt" + "reflect" + "sort" + "testing" "android/soong/android" "android/soong/cc" + "android/soong/python" + + "github.com/google/blueprint" ) func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) android.Config { @@ -38,6 +44,9 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string "prebuilts/sdk/17/public/android.jar": nil, "prebuilts/sdk/17/public/framework.aidl": nil, "prebuilts/sdk/17/system/android.jar": nil, + "prebuilts/sdk/28/public/android.jar": nil, + "prebuilts/sdk/28/public/framework.aidl": nil, + "prebuilts/sdk/28/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, @@ -81,12 +90,15 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string "prebuilts/sdk/tools/core-lambda-stubs.jar": nil, "prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "30", "current"],}`), + "bin.py": nil, + python.StubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%' + MAIN_FILE = '%main%'`), + // For java_sdk_library - "api/module-lib-current.txt": nil, - "api/module-lib-removed.txt": nil, - "api/system-server-current.txt": nil, - "api/system-server-removed.txt": nil, - "build/soong/scripts/gen-java-current-api-files.sh": nil, + "api/module-lib-current.txt": nil, + "api/module-lib-removed.txt": nil, + "api/system-server-current.txt": nil, + "api/system-server-removed.txt": nil, } cc.GatherRequiredFilesForTest(mockFS) @@ -118,7 +130,8 @@ func GatherRequiredDepsForTest() string { "android_module_lib_stubs_current", "android_system_server_stubs_current", "core.current.stubs", - "core.platform.api.stubs", + "legacy.core.platform.api.stubs", + "stable.core.platform.api.stubs", "kotlin-stdlib", "kotlin-stdlib-jdk7", "kotlin-stdlib-jdk8", @@ -131,7 +144,7 @@ func GatherRequiredDepsForTest() string { name: "%s", srcs: ["a.java"], sdk_version: "none", - system_modules: "core-platform-api-stubs-system-modules", + system_modules: "stable-core-platform-api-stubs-system-modules", } `, extra) } @@ -141,7 +154,7 @@ func GatherRequiredDepsForTest() string { name: "framework", srcs: ["a.java"], sdk_version: "none", - system_modules: "core-platform-api-stubs-system-modules", + system_modules: "stable-core-platform-api-stubs-system-modules", aidl: { export_include_dirs: ["framework/aidl"], }, @@ -156,7 +169,7 @@ func GatherRequiredDepsForTest() string { name: "android.hidl.base-V1.0-java", srcs: ["a.java"], sdk_version: "none", - system_modules: "core-platform-api-stubs-system-modules", + system_modules: "stable-core-platform-api-stubs-system-modules", installable: true, } @@ -164,7 +177,7 @@ func GatherRequiredDepsForTest() string { name: "android.hidl.manager-V1.0-java", srcs: ["a.java"], sdk_version: "none", - system_modules: "core-platform-api-stubs-system-modules", + system_modules: "stable-core-platform-api-stubs-system-modules", installable: true, } @@ -172,14 +185,31 @@ func GatherRequiredDepsForTest() string { name: "org.apache.http.legacy", srcs: ["a.java"], sdk_version: "none", - system_modules: "core-platform-api-stubs-system-modules", + system_modules: "stable-core-platform-api-stubs-system-modules", + installable: true, + } + + java_library { + name: "android.test.base", + srcs: ["a.java"], + sdk_version: "none", + system_modules: "stable-core-platform-api-stubs-system-modules", + installable: true, + } + + java_library { + name: "android.test.mock", + srcs: ["a.java"], + sdk_version: "none", + system_modules: "stable-core-platform-api-stubs-system-modules", installable: true, } ` systemModules := []string{ "core-current-stubs-system-modules", - "core-platform-api-stubs-system-modules", + "legacy-core-platform-api-stubs-system-modules", + "stable-core-platform-api-stubs-system-modules", } for _, extra := range systemModules { @@ -198,3 +228,17 @@ func GatherRequiredDepsForTest() string { return bp } + +func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) { + t.Helper() + module := ctx.ModuleForTests(name, variant).Module() + deps := []string{} + ctx.VisitDirectDeps(module, func(m blueprint.Module) { + deps = append(deps, m.Name()) + }) + sort.Strings(deps) + + if actual := deps; !reflect.DeepEqual(expected, actual) { + t.Errorf("expected %#q, found %#q", expected, actual) + } +} |