summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/Android.bp1
-rw-r--r--java/aapt2.go40
-rw-r--r--java/aar.go35
-rw-r--r--java/android_manifest.go4
-rw-r--r--java/androidmk.go15
-rw-r--r--java/androidmk_test.go177
-rwxr-xr-xjava/app.go47
-rw-r--r--java/app_test.go42
-rw-r--r--java/boot_jars.go6
-rw-r--r--java/builder.go9
-rw-r--r--java/device_host_converter.go6
-rw-r--r--java/dexpreopt.go2
-rw-r--r--java/dexpreopt_bootjars.go359
-rw-r--r--java/droiddoc.go85
-rw-r--r--java/gen.go4
-rw-r--r--java/hiddenapi.go6
-rw-r--r--java/hiddenapi_singleton.go35
-rw-r--r--java/java.go235
-rw-r--r--java/java_test.go232
-rw-r--r--java/kotlin.go4
-rw-r--r--java/kotlin_test.go158
-rw-r--r--java/lint.go18
-rw-r--r--java/platform_compat_config.go12
-rw-r--r--java/proto.go8
-rw-r--r--java/robolectric.go14
-rw-r--r--java/sdk.go12
-rw-r--r--java/sdk_library.go72
-rw-r--r--java/sdk_library_external.go109
-rw-r--r--java/sysprop.go4
29 files changed, 1176 insertions, 575 deletions
diff --git a/java/Android.bp b/java/Android.bp
index 9e8dc786b..39502b3e1 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -48,6 +48,7 @@ bootstrap_go_package {
"robolectric.go",
"sdk.go",
"sdk_library.go",
+ "sdk_library_external.go",
"support_libraries.go",
"sysprop.go",
"system_modules.go",
diff --git a/java/aapt2.go b/java/aapt2.go
index 04e4de52c..5346ddf89 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -25,12 +25,9 @@ import (
"android/soong/android"
)
-const AAPT2_SHARD_SIZE = 100
-
// Convert input resource file path to output file path.
// values-[config]/<file>.xml -> values-[config]_<file>.arsc.flat;
-// For other resource file, just replace the last "/" with "_" and
-// add .flat extension.
+// For other resource file, just replace the last "/" with "_" and add .flat extension.
func pathToAapt2Path(ctx android.ModuleContext, res android.Path) android.WritablePath {
name := res.Base()
@@ -43,6 +40,7 @@ func pathToAapt2Path(ctx android.ModuleContext, res android.Path) android.Writab
return android.PathForModuleOut(ctx, "aapt2", subDir, name)
}
+// pathsToAapt2Paths Calls pathToAapt2Path on each entry of the given Paths, i.e. []Path.
func pathsToAapt2Paths(ctx android.ModuleContext, resPaths android.Paths) android.WritablePaths {
outPaths := make(android.WritablePaths, len(resPaths))
@@ -53,6 +51,9 @@ func pathsToAapt2Paths(ctx android.ModuleContext, resPaths android.Paths) androi
return outPaths
}
+// Shard resource files for efficiency. See aapt2Compile for details.
+const AAPT2_SHARD_SIZE = 100
+
var aapt2CompileRule = pctx.AndroidStaticRule("aapt2Compile",
blueprint.RuleParams{
Command: `${config.Aapt2Cmd} compile -o $outDir $cFlags $in`,
@@ -60,14 +61,26 @@ var aapt2CompileRule = pctx.AndroidStaticRule("aapt2Compile",
},
"outDir", "cFlags")
+// aapt2Compile compiles resources and puts the results in the requested directory.
func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Paths,
flags []string) android.WritablePaths {
+ // Shard the input paths so that they can be processed in parallel. If we shard them into too
+ // small chunks, the additional cost of spinning up aapt2 outweighs the performance gain. The
+ // current shard size, 100, seems to be a good balance between the added cost and the gain.
+ // The aapt2 compile actions are trivially short, but each action in ninja takes on the order of
+ // ~10 ms to run. frameworks/base/core/res/res has >10k resource files, so compiling each one
+ // with an individual action could take 100 CPU seconds. Sharding them reduces the overhead of
+ // starting actions by a factor of 100, at the expense of recompiling more files when one
+ // changes. Since the individual compiles are trivial it's a good tradeoff.
shards := android.ShardPaths(paths, AAPT2_SHARD_SIZE)
ret := make(android.WritablePaths, 0, len(paths))
for i, shard := range shards {
+ // This should be kept in sync with pathToAapt2Path. The aapt2 compile command takes an
+ // output directory path, but not output file paths. So, outPaths is just where we expect
+ // the output files will be located.
outPaths := pathsToAapt2Paths(ctx, shard)
ret = append(ret, outPaths...)
@@ -82,6 +95,12 @@ func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Pat
Inputs: shard,
Outputs: outPaths,
Args: map[string]string{
+ // The aapt2 compile command takes an output directory path, but not output file paths.
+ // outPaths specified above is only used for dependency management purposes. In order for
+ // the outPaths values to match the actual outputs from aapt2, the dir parameter value
+ // must be a common prefix path of the paths values, and the top-level path segment used
+ // below, "aapt2", must always be kept in sync with the one in pathToAapt2Path.
+ // TODO(b/174505750): Make this easier and robust to use.
"outDir": android.PathForModuleOut(ctx, "aapt2", dir.String()).String(),
"cFlags": strings.Join(flags, " "),
},
@@ -104,6 +123,8 @@ var aapt2CompileZipRule = pctx.AndroidStaticRule("aapt2CompileZip",
},
}, "cFlags", "resZipDir", "zipSyncFlags")
+// Unzips the given compressed file and compiles the resource source files in it. The zipPrefix
+// parameter points to the subdirectory in the zip file where the resource files are located.
func aapt2CompileZip(ctx android.ModuleContext, flata android.WritablePath, zip android.Path, zipPrefix string,
flags []string) {
@@ -163,6 +184,7 @@ func aapt2Link(ctx android.ModuleContext,
var inFlags []string
if len(compiledRes) > 0 {
+ // Create a file that contains the list of all compiled resource file paths.
resFileList := android.PathForModuleOut(ctx, "aapt2", "res.list")
// Write out file lists to files
ctx.Build(pctx, android.BuildParams{
@@ -174,10 +196,12 @@ func aapt2Link(ctx android.ModuleContext,
deps = append(deps, compiledRes...)
deps = append(deps, resFileList)
+ // aapt2 filepath arguments that start with "@" mean file-list files.
inFlags = append(inFlags, "@"+resFileList.String())
}
if len(compiledOverlay) > 0 {
+ // Compiled overlay files are processed the same way as compiled resources.
overlayFileList := android.PathForModuleOut(ctx, "aapt2", "overlay.list")
ctx.Build(pctx, android.BuildParams{
Rule: fileListToFileRule,
@@ -188,9 +212,11 @@ func aapt2Link(ctx android.ModuleContext,
deps = append(deps, compiledOverlay...)
deps = append(deps, overlayFileList)
+ // Compiled overlay files are passed over to aapt2 using -R option.
inFlags = append(inFlags, "-R", "@"+overlayFileList.String())
}
+ // Set auxiliary outputs as implicit outputs to establish correct dependency chains.
implicitOutputs := append(splitPackages, proguardOptions, genJar, rTxt, extraPackages)
linkOutput := packageRes
@@ -212,6 +238,10 @@ func aapt2Link(ctx android.ModuleContext,
Implicits: deps,
Output: linkOutput,
ImplicitOutputs: implicitOutputs,
+ // Note the absence of splitPackages. The caller is supposed to compose and provide --split flag
+ // values via the flags parameter when it wants to split outputs.
+ // TODO(b/174509108): Perhaps we can process it in this func while keeping the code reasonably
+ // tidy.
Args: map[string]string{
"flags": strings.Join(flags, " "),
"inFlags": strings.Join(inFlags, " "),
@@ -230,6 +260,8 @@ var aapt2ConvertRule = pctx.AndroidStaticRule("aapt2Convert",
CommandDeps: []string{"${config.Aapt2Cmd}"},
})
+// Converts xml files and resource tables (resources.arsc) in the given jar/apk file to a proto
+// format. The proto definition is available at frameworks/base/tools/aapt2/Resources.proto.
func aapt2Convert(ctx android.ModuleContext, out android.WritablePath, in android.Path) {
ctx.Build(pctx, android.BuildParams{
Rule: aapt2ConvertRule,
diff --git a/java/aar.go b/java/aar.go
index 7c3840bb1..3b6b34e27 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -259,16 +259,16 @@ var extractAssetsRule = pctx.AndroidStaticRule("extractAssets",
})
func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext,
- sdkLibraries dexpreopt.ClassLoaderContextMap, extraLinkFlags ...string) {
+ classLoaderContexts dexpreopt.ClassLoaderContextMap, extraLinkFlags ...string) {
transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags :=
- aaptLibs(ctx, sdkContext, sdkLibraries)
+ aaptLibs(ctx, sdkContext, classLoaderContexts)
// App manifest file
manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
- manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, sdkLibraries,
+ manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, classLoaderContexts,
a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex, a.hasNoCode,
a.LoggingParent)
@@ -389,15 +389,15 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext,
}
// aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
-func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext, sdkLibraries dexpreopt.ClassLoaderContextMap) (
+func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap) (
transitiveStaticLibs, transitiveStaticLibManifests android.Paths, staticRRODirs []rroDir, assets, deps android.Paths, flags []string) {
var sharedLibs android.Paths
- if sdkLibraries == nil {
+ if classLoaderContexts == nil {
// Not all callers need to compute class loader context, those who don't just pass nil.
// Create a temporary class loader context here (it will be computed, but not used).
- sdkLibraries = make(dexpreopt.ClassLoaderContextMap)
+ classLoaderContexts = make(dexpreopt.ClassLoaderContextMap)
}
sdkDep := decodeSdkDep(ctx, sdkContext)
@@ -407,6 +407,7 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext, sdkLibraries dex
ctx.VisitDirectDeps(func(module android.Module) {
depName := ctx.OtherModuleName(module)
+ depTag := ctx.OtherModuleDependencyTag(module)
var exportPackage android.Path
aarDep, _ := module.(AndroidLibraryDependency)
@@ -414,7 +415,7 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext, sdkLibraries dex
exportPackage = aarDep.ExportPackage()
}
- switch ctx.OtherModuleDependencyTag(module) {
+ switch depTag {
case instrumentationForTag:
// Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2.
case libTag:
@@ -426,7 +427,7 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext, sdkLibraries dex
// (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.MaybeAddContext(ctx, component.OptionalImplicitSdkLibrary(),
+ classLoaderContexts.MaybeAddContext(ctx, component.OptionalImplicitSdkLibrary(),
component.DexJarBuildPath(), component.DexJarInstallPath())
}
@@ -439,7 +440,6 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext, sdkLibraries dex
transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...)
transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...)
- sdkLibraries.AddContextMap(aarDep.ExportedSdkLibs(), depName)
if aarDep.ExportedAssets().Valid() {
assets = append(assets, aarDep.ExportedAssets().Path())
}
@@ -458,11 +458,8 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext, sdkLibraries dex
}
}
- // Add nested dependencies after processing the direct dependency: if it is a <uses-library>,
- // nested context is added as its subcontext, and should not be re-added at the top-level.
- if dep, ok := module.(Dependency); ok {
- sdkLibraries.AddContextMap(dep.ExportedSdkLibs(), depName)
- }
+ // Merge dep's CLC after processing the dep itself (which may add its own <uses-library>).
+ maybeAddCLCFromDep(module, depTag, depName, classLoaderContexts)
})
deps = append(deps, sharedLibs...)
@@ -514,8 +511,8 @@ func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.aapt.isLibrary = true
- a.exportedSdkLibs = make(dexpreopt.ClassLoaderContextMap)
- a.aapt.buildActions(ctx, sdkContext(a), a.exportedSdkLibs)
+ a.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap)
+ a.aapt.buildActions(ctx, sdkContext(a), a.classLoaderContexts)
a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
@@ -832,12 +829,12 @@ func (a *AARImport) AidlIncludeDirs() android.Paths {
return nil
}
-func (a *AARImport) ExportedSdkLibs() dexpreopt.ClassLoaderContextMap {
+func (a *AARImport) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap {
return nil
}
-func (d *AARImport) ExportedPlugins() (android.Paths, []string) {
- return nil, nil
+func (d *AARImport) ExportedPlugins() (android.Paths, []string, bool) {
+ return nil, nil, false
}
func (a *AARImport) SrcJarArgs() ([]string, android.Paths) {
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 6b39c3584..c76bb2fda 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -44,7 +44,7 @@ var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger",
// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext,
- sdkLibraries dexpreopt.ClassLoaderContextMap, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis,
+ classLoaderContexts dexpreopt.ClassLoaderContextMap, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis,
useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path {
var args []string
@@ -71,7 +71,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext
args = append(args, "--use-embedded-dex")
}
- for _, usesLib := range sdkLibraries.UsesLibs() {
+ for _, usesLib := range classLoaderContexts.UsesLibs() {
if inList(usesLib, dexpreopt.OptionalCompatUsesLibs) {
args = append(args, "--optional-uses-library", usesLib)
} else {
diff --git a/java/androidmk.go b/java/androidmk.go
index c6062457f..fc573c8b6 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -85,7 +85,6 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries {
} else {
entriesList = append(entriesList, android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
- DistFiles: library.distFiles,
OutputFile: android.OptionalPathForPath(library.outputFile),
Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
@@ -115,7 +114,7 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries {
entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoReportClassesFile)
}
- entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.exportedSdkLibs.UsesLibs()...)
+ entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.classLoaderContexts.UsesLibs()...)
if len(library.additionalCheckedModules) != 0 {
entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...)
@@ -140,9 +139,9 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries {
func testSuiteComponent(entries *android.AndroidMkEntries, test_suites []string) {
entries.SetString("LOCAL_MODULE_TAGS", "tests")
if len(test_suites) > 0 {
- entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", test_suites...)
+ entries.AddCompatibilityTestSuites(test_suites...)
} else {
- entries.SetString("LOCAL_COMPATIBILITY_SUITE", "null-suite")
+ entries.AddCompatibilityTestSuites("null-suite")
}
}
@@ -160,6 +159,9 @@ func (j *Test) AndroidMkEntries() []android.AndroidMkEntries {
entries.SetString("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", "true")
}
entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", j.testProperties.Test_mainline_modules...)
+ if Bool(j.testProperties.Test_options.Unit_test) {
+ entries.SetBool("LOCAL_IS_UNIT_TEST", true)
+ }
})
return entriesList
@@ -521,17 +523,12 @@ func (dstubs *Droidstubs) AndroidMkEntries() []android.AndroidMkEntries {
// 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.
- var distFiles android.TaggedDistFiles
- if dstubs.apiFile != nil {
- distFiles = android.MakeDefaultDistFiles(dstubs.apiFile)
- }
outputFile := android.OptionalPathForPath(dstubs.stubsSrcJar)
if !outputFile.Valid() {
outputFile = android.OptionalPathForPath(dstubs.apiFile)
}
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
- DistFiles: distFiles,
OutputFile: outputFile,
Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
index 075b7aa6f..233e9d5c5 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -16,7 +16,6 @@ package java
import (
"reflect"
- "strings"
"testing"
"android/soong/android"
@@ -135,182 +134,6 @@ func TestHostdexSpecificRequired(t *testing.T) {
}
}
-func TestDistWithTag(t *testing.T) {
- ctx, config := testJava(t, `
- java_library {
- name: "foo_without_tag",
- srcs: ["a.java"],
- compile_dex: true,
- dist: {
- targets: ["hi"],
- },
- }
- java_library {
- name: "foo_with_tag",
- srcs: ["a.java"],
- compile_dex: true,
- dist: {
- targets: ["hi"],
- tag: ".jar",
- },
- }
- `)
-
- 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(withoutTagEntries) != 2 || len(withTagEntries) != 2 {
- t.Errorf("two mk entries per module expected, got %d and %d", len(withoutTagEntries), len(withTagEntries))
- }
- 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 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 {
diff --git a/java/app.go b/java/app.go
index 9ff413cc1..e6d9550ec 100755
--- a/java/app.go
+++ b/java/app.go
@@ -566,7 +566,7 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
a.aapt.splitNames = a.appProperties.Package_splits
a.aapt.LoggingParent = String(a.overridableAppProperties.Logging_parent)
- a.aapt.buildActions(ctx, sdkContext(a), a.exportedSdkLibs, aaptLinkFlags...)
+ a.aapt.buildActions(ctx, sdkContext(a), a.classLoaderContexts, aaptLinkFlags...)
// apps manifests are handled by aapt, don't let Module see them
a.properties.Manifest = nil
@@ -608,7 +608,7 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
}
a.dexpreopter.uncompressedDex = *a.dexProperties.Uncompress_dex
a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
- a.dexpreopter.classLoaderContexts = a.exportedSdkLibs
+ a.dexpreopter.classLoaderContexts = a.classLoaderContexts
a.dexpreopter.manifestFile = a.mergedManifestFile
if ctx.ModuleName() != "framework-res" {
@@ -779,7 +779,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
a.aapt.noticeFile = a.noticeOutputs.HtmlGzOutput
}
- a.exportedSdkLibs = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
+ a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
// Process all building blocks, from AAPT to certificates.
a.aaptBuildActions(ctx)
@@ -788,7 +788,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
a.usesLibrary.freezeEnforceUsesLibraries()
// Add implicit SDK libraries to <uses-library> list.
- for _, usesLib := range a.exportedSdkLibs.UsesLibs() {
+ for _, usesLib := range a.classLoaderContexts.UsesLibs() {
a.usesLibrary.addLib(usesLib, inList(usesLib, dexpreopt.OptionalCompatUsesLibs))
}
@@ -890,7 +890,7 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface,
if IsJniDepTag(tag) || cc.IsSharedDepTag(tag) {
if dep, ok := module.(*cc.Module); ok {
- if dep.IsNdk() || dep.IsStubs() {
+ if dep.IsNdk(ctx.Config()) || dep.IsStubs() {
return false
}
@@ -1115,8 +1115,8 @@ func (a *AndroidTest) FixTestConfig(ctx android.ModuleContext, testConfig androi
}
fixedConfig := android.PathForModuleOut(ctx, "test_config_fixer", "AndroidTest.xml")
- rule := android.NewRuleBuilder()
- command := rule.Command().BuiltTool(ctx, "test_config_fixer").Input(testConfig).Output(fixedConfig)
+ rule := android.NewRuleBuilder(pctx, ctx)
+ command := rule.Command().BuiltTool("test_config_fixer").Input(testConfig).Output(fixedConfig)
fixNeeded := false
if ctx.ModuleName() != a.installApkName {
@@ -1131,7 +1131,7 @@ func (a *AndroidTest) FixTestConfig(ctx android.ModuleContext, testConfig androi
}
if fixNeeded {
- rule.Build(pctx, ctx, "fix_test_config", "fix test config")
+ rule.Build("fix_test_config", "fix test config")
return fixedConfig
}
return testConfig
@@ -1400,6 +1400,13 @@ func (a *AndroidAppImport) processVariants(ctx android.LoadHookContext) {
archProps := reflect.ValueOf(a.archVariants).Elem().FieldByName("Arch")
archType := ctx.Config().AndroidFirstDeviceTarget.Arch.ArchType
MergePropertiesFromVariant(ctx, &a.properties, archProps, archType.Name)
+
+ if String(a.properties.Apk) == "" {
+ // Disable this module since the apk property is still empty after processing all matching
+ // variants. This likely means there is no matching variant, and the default variant doesn't
+ // have an apk property value either.
+ a.Disable()
+ }
}
func MergePropertiesFromVariant(ctx android.EarlyModuleContext,
@@ -1440,15 +1447,15 @@ func (a *AndroidAppImport) uncompressEmbeddedJniLibs(
})
return
}
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
Textf(`if (zipinfo %s 'lib/*.so' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, inputPath).
- BuiltTool(ctx, "zip2zip").
+ BuiltTool("zip2zip").
FlagWithInput("-i ", inputPath).
FlagWithOutput("-o ", outputPath).
FlagWithArg("-0 ", "'lib/**/*.so'").
Textf(`; else cp -f %s %s; fi`, inputPath, outputPath)
- rule.Build(pctx, ctx, "uncompress-embedded-jni-libs", "Uncompress embedded JIN libs")
+ rule.Build("uncompress-embedded-jni-libs", "Uncompress embedded JIN libs")
}
// Returns whether this module should have the dex file stored uncompressed in the APK.
@@ -1467,15 +1474,15 @@ func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool {
func (a *AndroidAppImport) uncompressDex(
ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
Textf(`if (zipinfo %s '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, inputPath).
- BuiltTool(ctx, "zip2zip").
+ BuiltTool("zip2zip").
FlagWithInput("-i ", inputPath).
FlagWithOutput("-o ", outputPath).
FlagWithArg("-0 ", "'classes*.dex'").
Textf(`; else cp -f %s %s; fi`, inputPath, outputPath)
- rule.Build(pctx, ctx, "uncompress-dex", "Uncompress dex files")
+ rule.Build("uncompress-dex", "Uncompress dex files")
}
func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -1982,7 +1989,7 @@ func (u *usesLibrary) classLoaderContextForUsesLibDeps(ctx android.ModuleContext
dep := ctx.OtherModuleName(m)
if lib, ok := m.(Dependency); ok {
clcMap.AddContextForSdk(ctx, tag.sdkVersion, dep,
- lib.DexJarBuildPath(), lib.DexJarInstallPath(), lib.ExportedSdkLibs())
+ lib.DexJarBuildPath(), lib.DexJarInstallPath(), lib.ClassLoaderContexts())
} else if ctx.Config().AllowMissingDependencies() {
ctx.AddMissingDependencies([]string{dep})
} else {
@@ -2015,8 +2022,8 @@ func (u *usesLibrary) freezeEnforceUsesLibraries() {
func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path) android.Path {
outputFile := android.PathForModuleOut(ctx, "manifest_check", "AndroidManifest.xml")
- rule := android.NewRuleBuilder()
- cmd := rule.Command().BuiltTool(ctx, "manifest_check").
+ rule := android.NewRuleBuilder(pctx, ctx)
+ cmd := rule.Command().BuiltTool("manifest_check").
Flag("--enforce-uses-libraries").
Input(manifest).
FlagWithOutput("-o ", outputFile)
@@ -2029,7 +2036,7 @@ func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, man
cmd.FlagWithArg("--optional-uses-library ", lib)
}
- rule.Build(pctx, ctx, "verify_uses_libraries", "verify <uses-library>")
+ rule.Build("verify_uses_libraries", "verify <uses-library>")
return outputFile
}
@@ -2039,7 +2046,7 @@ func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, man
func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) android.Path {
outputFile := android.PathForModuleOut(ctx, "verify_uses_libraries", apk.Base())
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
aapt := ctx.Config().HostToolPath(ctx, "aapt")
rule.Command().
Textf("aapt_binary=%s", aapt.String()).Implicit(aapt).
@@ -2048,7 +2055,7 @@ func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk andr
Tool(android.PathForSource(ctx, "build/make/core/verify_uses_libraries.sh")).Input(apk)
rule.Command().Text("cp -f").Input(apk).Output(outputFile)
- rule.Build(pctx, ctx, "verify_uses_libraries", "verify <uses-library>")
+ rule.Build("verify_uses_libraries", "verify <uses-library>")
return outputFile
}
diff --git a/java/app_test.go b/java/app_test.go
index 6429ab836..ef5e84dd2 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -291,7 +291,7 @@ func TestAndroidAppLinkType(t *testing.T) {
}
`)
- testJavaError(t, "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.", `
+ testJavaError(t, "consider adjusting sdk_version: OR platform_apis:", `
android_app {
name: "foo",
srcs: ["a.java"],
@@ -335,7 +335,7 @@ func TestAndroidAppLinkType(t *testing.T) {
}
`)
- testJavaError(t, "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.", `
+ testJavaError(t, "consider adjusting sdk_version: OR platform_apis:", `
android_app {
name: "foo",
srcs: ["a.java"],
@@ -2524,6 +2524,24 @@ func TestAndroidAppImport_ArchVariants(t *testing.T) {
`,
expected: "prebuilts/apk/app.apk",
},
+ {
+ name: "no matching arch without default",
+ bp: `
+ android_app_import {
+ name: "foo",
+ arch: {
+ arm: {
+ apk: "prebuilts/apk/app_arm.apk",
+ },
+ },
+ presigned: true,
+ dex_preopt: {
+ enabled: true,
+ },
+ }
+ `,
+ expected: "",
+ },
}
jniRuleRe := regexp.MustCompile("^if \\(zipinfo (\\S+)")
@@ -2531,6 +2549,12 @@ func TestAndroidAppImport_ArchVariants(t *testing.T) {
ctx, _ := testJava(t, test.bp)
variant := ctx.ModuleForTests("foo", "android_common")
+ if test.expected == "" {
+ if variant.Module().Enabled() {
+ t.Error("module should have been disabled, but wasn't")
+ }
+ continue
+ }
jniRuleCommand := variant.Output("jnis-uncompressed/foo.apk").RuleParams.Command
matches := jniRuleRe.FindStringSubmatch(jniRuleCommand)
if len(matches) != 2 {
@@ -2730,6 +2754,13 @@ func TestUsesLibraries(t *testing.T) {
}
java_sdk_library {
+ name: "fred",
+ srcs: ["a.java"],
+ api_packages: ["fred"],
+ sdk_version: "current",
+ }
+
+ java_sdk_library {
name: "bar",
srcs: ["a.java"],
api_packages: ["bar"],
@@ -2753,7 +2784,12 @@ func TestUsesLibraries(t *testing.T) {
name: "app",
srcs: ["a.java"],
libs: ["qux", "quuz.stubs"],
- static_libs: ["static-runtime-helper"],
+ static_libs: [
+ "static-runtime-helper",
+ // statically linked component libraries should not pull their SDK libraries,
+ // so "fred" should not be added to class loader context
+ "fred.stubs",
+ ],
uses_libs: ["foo"],
sdk_version: "current",
optional_uses_libs: [
diff --git a/java/boot_jars.go b/java/boot_jars.go
index e70654781..823275b1d 100644
--- a/java/boot_jars.go
+++ b/java/boot_jars.go
@@ -85,8 +85,8 @@ func (b *bootJarsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
timestamp := android.PathForOutput(ctx, "boot-jars-package-check/stamp")
- rule := android.NewRuleBuilder()
- checkBootJars := rule.Command().BuiltTool(ctx, "check_boot_jars").
+ rule := android.NewRuleBuilder(pctx, ctx)
+ checkBootJars := rule.Command().BuiltTool("check_boot_jars").
Input(ctx.Config().HostToolPath(ctx, "dexdump")).
Input(android.PathForSource(ctx, "build/soong/scripts/check_boot_jars/package_allowed_list.txt"))
@@ -109,7 +109,7 @@ func (b *bootJarsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
}
checkBootJars.Text("&& touch").Output(timestamp)
- rule.Build(pctx, ctx, "boot_jars_package_check", "check boot jar packages")
+ rule.Build("boot_jars_package_check", "check boot jar packages")
// The check-boot-jars phony target depends on the timestamp created if the check succeeds.
ctx.Phony("check-boot-jars", timestamp)
diff --git a/java/builder.go b/java/builder.go
index 3043e46db..cd3524542 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -572,14 +572,7 @@ func TransformJetifier(ctx android.ModuleContext, outputFile android.WritablePat
}
func GenerateMainClassManifest(ctx android.ModuleContext, outputFile android.WritablePath, mainClass string) {
- ctx.Build(pctx, android.BuildParams{
- Rule: android.WriteFile,
- Description: "manifest",
- Output: outputFile,
- Args: map[string]string{
- "content": "Main-Class: " + mainClass + "\n",
- },
- })
+ android.WriteFileRule(ctx, outputFile, "Main-Class: "+mainClass+"\n")
}
func TransformZipAlign(ctx android.ModuleContext, outputFile android.WritablePath, inputFile android.Path) {
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index d8b617e7d..4914d74f6 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -163,12 +163,12 @@ func (d *DeviceHostConverter) AidlIncludeDirs() android.Paths {
return nil
}
-func (d *DeviceHostConverter) ExportedSdkLibs() dexpreopt.ClassLoaderContextMap {
+func (d *DeviceHostConverter) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap {
return nil
}
-func (d *DeviceHostConverter) ExportedPlugins() (android.Paths, []string) {
- return nil, nil
+func (d *DeviceHostConverter) ExportedPlugins() (android.Paths, []string, bool) {
+ return nil, nil, false
}
func (d *DeviceHostConverter) SrcJarArgs() ([]string, android.Paths) {
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index a21fb7640..67738d49b 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -216,7 +216,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo
return dexJarFile
}
- dexpreoptRule.Build(pctx, ctx, "dexpreopt", "dexpreopt")
+ dexpreoptRule.Build("dexpreopt", "dexpreopt")
d.builtInstalled = dexpreoptRule.Installs().String()
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 629d34f25..062005b5b 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -25,11 +25,177 @@ import (
"github.com/google/blueprint/proptools"
)
+// This comment describes:
+// 1. ART boot images in general (their types, structure, file layout, etc.)
+// 2. build system support for boot images
+//
+// 1. ART boot images
+// ------------------
+//
+// A boot image in ART is a set of files that contain AOT-compiled native code and a heap snapshot
+// of AOT-initialized classes for the bootclasspath Java libraries. A boot image is compiled from a
+// set of DEX jars by the dex2oat compiler. A boot image is used for two purposes: 1) it is
+// installed on device and loaded at runtime, and 2) other Java libraries and apps are compiled
+// against it (compilation may take place either on host, known as "dexpreopt", or on device, known
+// as "dexopt").
+//
+// A boot image is not a single file, but a collection of interrelated files. Each boot image has a
+// number of components that correspond to the Java libraries that constitute it. For each component
+// there are multiple files:
+// - *.oat or *.odex file with native code (architecture-specific, one per instruction set)
+// - *.art file with pre-initialized Java classes (architecture-specific, one per instruction set)
+// - *.vdex file with verification metadata for the DEX bytecode (architecture independent)
+//
+// *.vdex files for the boot images do not contain the DEX bytecode itself, because the
+// bootclasspath DEX files are stored on disk in uncompressed and aligned form. Consequently a boot
+// image is not self-contained and cannot be used without its DEX files. To simplify the management
+// of boot image files, ART uses a certain naming scheme and associates the following metadata with
+// each boot image:
+// - A stem, which is a symbolic name that is prepended to boot image file names.
+// - A location (on-device path to the boot image files).
+// - A list of boot image locations (on-device paths to dependency boot images).
+// - A set of DEX locations (on-device paths to the DEX files, one location for one DEX file used
+// to compile the boot image).
+//
+// There are two kinds of boot images:
+// - primary boot images
+// - boot image extensions
+//
+// 1.1. Primary boot images
+// ------------------------
+//
+// A primary boot image is compiled for a core subset of bootclasspath Java libraries. It does not
+// depend on any other images, and other boot images may depend on it.
+//
+// For example, assuming that the stem is "boot", the location is /apex/com.android.art/javalib/,
+// the set of core bootclasspath libraries is A B C, and the boot image is compiled for ARM targets
+// (32 and 64 bits), it will have three components with the following files:
+// - /apex/com.android.art/javalib/{arm,arm64}/boot.{art,oat,vdex}
+// - /apex/com.android.art/javalib/{arm,arm64}/boot-B.{art,oat,vdex}
+// - /apex/com.android.art/javalib/{arm,arm64}/boot-C.{art,oat,vdex}
+//
+// The files of the first component are special: they do not have the component name appended after
+// the stem. This naming convention dates back to the times when the boot image was not split into
+// components, and there were just boot.oat and boot.art. The decision to split was motivated by
+// licensing reasons for one of the bootclasspath libraries.
+//
+// As of November 2020 the only primary boot image in Android is the image in the ART APEX
+// com.android.art. The primary ART boot image contains the Core libraries that are part of the ART
+// module. When the ART module gets updated, the primary boot image will be updated with it, and all
+// dependent images will get invalidated (the checksum of the primary image stored in dependent
+// images will not match), unless they are updated in sync with the ART module.
+//
+// 1.2. Boot image extensions
+// --------------------------
+//
+// A boot image extension is compiled for a subset of bootclasspath Java libraries (in particular,
+// this subset does not include the Core bootclasspath libraries that go into the primary boot
+// image). A boot image extension depends on the primary boot image and optionally some other boot
+// image extensions. Other images may depend on it. In other words, boot image extensions can form
+// acyclic dependency graphs.
+//
+// The motivation for boot image extensions comes from the Mainline project. Consider a situation
+// when the list of bootclasspath libraries is A B C, and both A and B are parts of the Android
+// platform, but C is part of an updatable APEX com.android.C. When the APEX is updated, the Java
+// code for C might have changed compared to the code that was used to compile the boot image.
+// Consequently, the whole boot image is obsolete and invalidated (even though the code for A and B
+// that does not depend on C is up to date). To avoid this, the original monolithic boot image is
+// split in two parts: the primary boot image that contains A B, and the boot image extension that
+// contains C and depends on the primary boot image (extends it).
+//
+// For example, assuming that the stem is "boot", the location is /system/framework, the set of
+// bootclasspath libraries is D E (where D is part of the platform and is located in
+// /system/framework, and E is part of a non-updatable APEX com.android.E and is located in
+// /apex/com.android.E/javalib), and the boot image is compiled for ARM targets (32 and 64 bits),
+// it will have two components with the following files:
+// - /system/framework/{arm,arm64}/boot-D.{art,oat,vdex}
+// - /system/framework/{arm,arm64}/boot-E.{art,oat,vdex}
+//
+// As of November 2020 the only boot image extension in Android is the Framework boot image
+// extension. It extends the primary ART boot image and contains Framework libraries and other
+// bootclasspath libraries from the platform and non-updatable APEXes that are not included in the
+// ART image. The Framework boot image extension is updated together with the platform. In the
+// future other boot image extensions may be added for some updatable modules.
+//
+//
+// 2. Build system support for boot images
+// ---------------------------------------
+//
+// The primary ART boot image needs to be compiled with one dex2oat invocation that depends on DEX
+// jars for the core libraries. Framework boot image extension needs to be compiled with one dex2oat
+// invocation that depends on the primary ART boot image and all bootclasspath DEX jars except the
+// Core libraries.
+//
+// 2.1. Libraries that go in the boot images
+// -----------------------------------------
+//
+// The contents of each boot image are determined by the PRODUCT variables. The primary ART APEX
+// boot image contains libraries listed in the ART_APEX_JARS variable in the AOSP makefiles. The
+// Framework boot image extension contains libraries specified in the PRODUCT_BOOT_JARS and
+// PRODUCT_BOOT_JARS_EXTRA variables. The AOSP makefiles specify some common Framework libraries,
+// but more product-specific libraries can be added in the product makefiles.
+//
+// Each component of the PRODUCT_BOOT_JARS and PRODUCT_BOOT_JARS_EXTRA variables is either a simple
+// name (if the library is a part of the Platform), or a colon-separated pair <apex, name> (if the
+// library is a part of a non-updatable APEX).
+//
+// A related variable PRODUCT_UPDATABLE_BOOT_JARS contains bootclasspath libraries that are in
+// updatable APEXes. They are not included in the boot image.
+//
+// One exception to the above rules are "coverage" builds (a special build flavor which requires
+// setting environment variable EMMA_INSTRUMENT_FRAMEWORK=true). In coverage builds the Java code in
+// boot image libraries is instrumented, which means that the instrumentation library (jacocoagent)
+// needs to be added to the list of bootclasspath DEX jars.
+//
+// In general, there is a requirement that the source code for a boot image library must be
+// available at build time (e.g. it cannot be a stub that has a separate implementation library).
+//
+// 2.2. Static configs
+// -------------------
+//
+// Because boot images are used to dexpreopt other Java modules, the paths to boot image files must
+// be known by the time dexpreopt build rules for the dependent modules are generated. Boot image
+// configs are constructed very early during the build, before build rule generation. The configs
+// provide predefined paths to boot image files (these paths depend only on static build
+// configuration, such as PRODUCT variables, and use hard-coded directory names).
+//
+// 2.3. Singleton
+// --------------
+//
+// Build rules for the boot images are generated with a Soong singleton. Because a singleton has no
+// dependencies on other modules, it has to find the modules for the DEX jars using VisitAllModules.
+// Soong loops through all modules and compares each module against a list of bootclasspath library
+// names. Then it generates build rules that copy DEX jars from their intermediate module-specific
+// locations to the hard-coded locations predefined in the boot image configs.
+//
+// It would be possible to use a module with proper dependencies instead, but that would require
+// changes in the way Soong generates variables for Make: a singleton can use one MakeVars() method
+// that writes variables to out/soong/make_vars-*.mk, which is included early by the main makefile,
+// but module(s) would have to use out/soong/Android-*.mk which has a group of LOCAL_* variables
+// for each module, and is included later.
+//
+// 2.4. Install rules
+// ------------------
+//
+// The primary boot image and the Framework extension are installed in different ways. The primary
+// boot image is part of the ART APEX: it is copied into the APEX intermediate files, packaged
+// together with other APEX contents, extracted and mounted on device. The Framework boot image
+// extension is installed by the rules defined in makefiles (make/core/dex_preopt_libart.mk). Soong
+// writes out a few DEXPREOPT_IMAGE_* variables for Make; these variables contain boot image names,
+// paths and so on.
+//
+// 2.5. JIT-Zygote configuration
+// -----------------------------
+//
+// One special configuration is JIT-Zygote build, when the primary ART image is used for compiling
+// apps instead of the Framework boot image extension (see DEXPREOPT_USE_ART_IMAGE and UseArtImage).
+//
+
func init() {
RegisterDexpreoptBootJarsComponents(android.InitRegistrationContext)
}
-// Target-independent description of pre-compiled boot image.
+// Target-independent description of a boot image.
type bootImageConfig struct {
// If this image is an extension, the image that it extends.
extends *bootImageConfig
@@ -66,7 +232,7 @@ type bootImageConfig struct {
variants []*bootImageVariant
}
-// Target-dependent description of pre-compiled boot image.
+// Target-dependent description of a boot image.
type bootImageVariant struct {
*bootImageConfig
@@ -90,6 +256,7 @@ type bootImageVariant struct {
unstrippedInstalls android.RuleBuilderInstalls
}
+// Get target-specific boot image variant for the given boot image config and target.
func (image bootImageConfig) getVariant(target android.Target) *bootImageVariant {
for _, variant := range image.variants {
if variant.target.Os == target.Os && variant.target.Arch.ArchType == target.Arch.ArchType {
@@ -99,7 +266,7 @@ func (image bootImageConfig) getVariant(target android.Target) *bootImageVariant
return nil
}
-// Return any (the first) variant which is for the device (as opposed to for the host)
+// 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 {
@@ -109,10 +276,12 @@ func (image bootImageConfig) getAnyAndroidVariant() *bootImageVariant {
return nil
}
+// Return the name of a boot image module given a boot image config and a component (module) index.
+// A module name is a combination of the Java library name, and the boot image stem (that is stored
+// in the config).
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.
+ // The first module of the primary boot image is special: its module name has only the stem, but
+ // not the library name. All other module names are of the form <stem>-<library name>
m := image.modules.Jar(idx)
name := image.stem
if idx != 0 || image.extends != nil {
@@ -121,6 +290,7 @@ func (image bootImageConfig) moduleName(ctx android.PathContext, idx int) string
return name
}
+// Return the name of the first boot image module, or stem if the list of modules is empty.
func (image bootImageConfig) firstModuleNameOrStem(ctx android.PathContext) string {
if image.modules.Len() > 0 {
return image.moduleName(ctx, 0)
@@ -129,6 +299,8 @@ func (image bootImageConfig) firstModuleNameOrStem(ctx android.PathContext) stri
}
}
+// Return filenames for the given boot image component, given the output directory and a list of
+// extensions.
func (image bootImageConfig) moduleFiles(ctx android.PathContext, dir android.OutputPath, exts ...string) android.OutputPaths {
ret := make(android.OutputPaths, 0, image.modules.Len()*len(exts))
for i := 0; i < image.modules.Len(); i++ {
@@ -140,17 +312,26 @@ func (image bootImageConfig) moduleFiles(ctx android.PathContext, dir android.Ou
return ret
}
+// Return boot image locations (as a list of symbolic paths).
+//
// 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).
+// 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).
+//
+// For a primary boot image the list of locations has a single element.
+//
+// For a boot image extension the list of locations contains a location for all dependency images
+// (including the primary image) and the location of the extension itself. For example, for the
+// Framework boot image extension that depends on the primary ART boot image the list contains two
+// elements.
//
// 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()
@@ -158,18 +339,6 @@ func (image *bootImageVariant) imageLocations() (imageLocations []string) {
return append(imageLocations, dexpreopt.PathToLocation(image.images, image.target.Arch.ArchType))
}
-func concat(lists ...[]string) []string {
- var size int
- for _, l := range lists {
- size += len(l)
- }
- ret := make([]string, 0, size)
- for _, l := range lists {
- ret = append(ret, l...)
- }
- return ret
-}
-
func dexpreoptBootJarsFactory() android.Singleton {
return &dexpreoptBootJars{}
}
@@ -182,10 +351,21 @@ func skipDexpreoptBootJars(ctx android.PathContext) bool {
return dexpreopt.GetGlobalConfig(ctx).DisablePreopt
}
+// Singleton for generating boot image build rules.
type dexpreoptBootJars struct {
+ // Default boot image config (currently always the Framework boot image extension). It should be
+ // noted that JIT-Zygote builds use ART APEX image instead of the Framework boot image extension,
+ // but the switch is handled not here, but in the makefiles (triggered with
+ // DEXPREOPT_USE_ART_IMAGE=true).
defaultBootImage *bootImageConfig
- otherImages []*bootImageConfig
+ // Other boot image configs (currently the list contains only the primary ART APEX image. It
+ // used to contain an experimental JIT-Zygote image (now replaced with the ART APEX image). In
+ // the future other boot image extensions may be added.
+ otherImages []*bootImageConfig
+
+ // Build path to a config file that Soong writes for Make (to be used in makefiles that install
+ // the default boot image).
dexpreoptConfigForMake android.WritablePath
}
@@ -205,7 +385,7 @@ func DexpreoptedArtApexJars(ctx android.BuilderContext) map[android.ArchType]and
return files
}
-// dexpreoptBoot singleton rules
+// Generate build rules for boot images.
func (d *dexpreoptBootJars) GenerateBuildActions(ctx android.SingletonContext) {
if skipDexpreoptBootJars(ctx) {
return
@@ -238,43 +418,53 @@ func (d *dexpreoptBootJars) GenerateBuildActions(ctx android.SingletonContext) {
dumpOatRules(ctx, d.defaultBootImage)
}
-func isHostdex(module android.Module) bool {
- if lib, ok := module.(*Library); ok {
- return Bool(lib.deviceProperties.Hostdex)
- }
- return false
-}
-
// Inspect this module to see if it contains a bootclasspath dex jar.
// Note that the same jar may occur in multiple modules.
// This logic is tested in the apex package to avoid import cycle apex <-> java.
func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, module android.Module) (int, android.Path) {
- // All apex Java libraries have non-installable platform variants, skip them.
- if module.IsSkipInstall() {
+ // Ignore any module that is not listed in the boot image configuration.
+ name := ctx.ModuleName(module)
+ index := image.modules.IndexOfJar(name)
+ if index == -1 {
return -1, nil
}
+ // It is an error if a module configured in the boot image does not support
+ // accessing the dex jar. This is safe because every module that has the same
+ // name has to have the same module type.
jar, hasJar := module.(interface{ DexJarBuildPath() android.Path })
if !hasJar {
+ ctx.Errorf("module %q configured in boot image %q does not support accessing dex jar", module, image.name)
return -1, nil
}
- name := ctx.ModuleName(module)
- index := image.modules.IndexOfJar(name)
- if index == -1 {
+ // It is also an error if the module is not an ApexModule.
+ if _, ok := module.(android.ApexModule); !ok {
+ ctx.Errorf("module %q configured in boot image %q does not support being added to an apex", module, image.name)
return -1, nil
}
- // Check that this module satisfies constraints for a particular boot image.
- _, isApexModule := module.(android.ApexModule)
apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
- fromUpdatableApex := isApexModule && apexInfo.Updatable
- if image.name == artBootImageName {
- if isApexModule && len(apexInfo.InApexes) > 0 && allHavePrefix(apexInfo.InApexes, "com.android.art") {
- // ok: found the jar in the ART apex
- } else if isApexModule && apexInfo.IsForPlatform() && isHostdex(module) {
- // exception (skip and continue): special "hostdex" platform variant
+
+ // Now match the apex part of the boot image configuration.
+ requiredApex := image.modules.Apex(index)
+ if requiredApex == "platform" {
+ if len(apexInfo.InApexes) != 0 {
+ // A platform variant is required but this is for an apex so ignore it.
return -1, nil
+ }
+ } else if !android.InList(requiredApex, apexInfo.InApexes) {
+ // An apex variant for a specific apex is required but this is the wrong apex.
+ return -1, nil
+ }
+
+ // Check that this module satisfies any boot image specific constraints.
+ fromUpdatableApex := apexInfo.Updatable
+
+ switch image.name {
+ case artBootImageName:
+ if len(apexInfo.InApexes) > 0 && allHavePrefix(apexInfo.InApexes, "com.android.art") {
+ // ok: found the jar in the ART apex
} else if name == "jacocoagent" && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
// exception (skip and continue): Jacoco platform variant for a coverage build
return -1, nil
@@ -285,14 +475,15 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul
// error: this jar is part of the platform or a non-updatable apex
ctx.Errorf("module %q is not allowed in the ART boot image", name)
}
- } else if image.name == frameworkBootImageName {
+
+ case 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 %q from updatable apexes %q is not allowed in the framework boot image", name, apexInfo.InApexes)
}
- } else {
+ default:
panic("unknown boot image: " + image.name)
}
@@ -315,6 +506,12 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootI
bootDexJars := make(android.Paths, image.modules.Len())
ctx.VisitAllModules(func(module android.Module) {
if i, j := getBootImageJar(ctx, image, module); i != -1 {
+ if existing := bootDexJars[i]; existing != nil {
+ ctx.Errorf("Multiple dex jars found for %s:%s - %s and %s",
+ image.modules.Apex(i), image.modules.Jar(i), existing, j)
+ return
+ }
+
bootDexJars[i] = j
}
})
@@ -326,7 +523,7 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootI
m := image.modules.Jar(i)
if ctx.Config().AllowMissingDependencies() {
missingDeps = append(missingDeps, m)
- bootDexJars[i] = android.PathForOutput(ctx, "missing")
+ bootDexJars[i] = android.PathForOutput(ctx, "missing/module", m, "from/apex", image.modules.Apex(i))
} else {
ctx.Errorf("failed to find a dex jar path for module '%s'"+
", note that some jars may be filtered out by module constraints", m)
@@ -334,9 +531,10 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootI
}
}
- // The path to bootclasspath dex files needs to be known at module GenerateAndroidBuildAction time, before
- // the bootclasspath modules have been compiled. Copy the dex jars there so the module rules that have
- // already been set up can find them.
+ // The paths to bootclasspath DEX files need to be known at module GenerateAndroidBuildAction
+ // time, before the boot images are built (these paths are used in dexpreopt rule generation for
+ // Java libraries and apps). Generate rules that copy bootclasspath DEX jars to the predefined
+ // paths.
for i := range bootDexJars {
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
@@ -358,19 +556,20 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootI
}
if image.zip != nil {
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
- BuiltTool(ctx, "soong_zip").
+ BuiltTool("soong_zip").
FlagWithOutput("-o ", image.zip).
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")
+ rule.Build("zip_"+image.name, "zip "+image.name+" image")
}
return image
}
+// Generate boot image build rules for a specific target.
func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant,
profile android.Path, missingDeps []string) android.WritablePaths {
@@ -386,7 +585,7 @@ func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant
oatLocation := dexpreopt.PathToLocation(outputPath, arch)
imagePath := outputPath.ReplaceExtension(ctx, "art")
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.MissingDeps(missingDeps)
rule.Command().Text("mkdir").Flag("-p").Flag(symbolsDir.String())
@@ -428,12 +627,15 @@ func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant
}
if image.extends != nil {
+ // It is a boot image extension, so it needs the boot image it depends on (in this case the
+ // primary ART APEX image).
artImage := image.primaryImages
cmd.
Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", image.dexLocationsDeps, ":").
FlagWithArg("--boot-image=", dexpreopt.PathToLocation(artImage, arch)).Implicit(artImage)
} else {
+ // It is a primary image, so it needs a base address.
cmd.FlagWithArg("--base=", ctx.Config().LibartImgDeviceBaseAddress())
}
@@ -504,7 +706,7 @@ func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant
android.RuleBuilderInstall{unstrippedOat, filepath.Join(installDir, unstrippedOat.Base())})
}
- rule.Build(pctx, ctx, image.name+"JarsDexpreopt_"+image.target.String(), "dexpreopt "+image.name+" jars "+arch.String())
+ rule.Build(image.name+"JarsDexpreopt_"+image.target.String(), "dexpreopt "+image.name+" jars "+arch.String())
// save output and installed files for makevars
image.installs = rule.Installs()
@@ -528,7 +730,7 @@ func bootImageProfileRule(ctx android.SingletonContext, image *bootImageConfig,
profile := ctx.Config().Once(bootImageProfileRuleKey, func() interface{} {
defaultProfile := "frameworks/base/config/boot-image-profile.txt"
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.MissingDeps(missingDeps)
var bootImageProfile android.Path
@@ -559,7 +761,7 @@ func bootImageProfileRule(ctx android.SingletonContext, image *bootImageConfig,
rule.Install(profile, "/system/etc/boot-image.prof")
- rule.Build(pctx, ctx, "bootJarsProfile", "profile boot jars")
+ rule.Build("bootJarsProfile", "profile boot jars")
image.profileInstalls = rule.Installs()
@@ -581,7 +783,7 @@ func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImageConf
return nil
}
return ctx.Config().Once(bootFrameworkProfileRuleKey, func() interface{} {
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.MissingDeps(missingDeps)
// Some branches like master-art-host don't have frameworks/base, so manually
@@ -594,7 +796,7 @@ func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImageConf
bootFrameworkProfile = path.Path()
} else {
missingDeps = append(missingDeps, defaultProfile)
- bootFrameworkProfile = android.PathForOutput(ctx, "missing")
+ bootFrameworkProfile = android.PathForOutput(ctx, "missing", defaultProfile)
}
profile := image.dir.Join(ctx, "boot.bprof")
@@ -609,7 +811,7 @@ func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImageConf
FlagWithOutput("--reference-profile-file=", profile)
rule.Install(profile, "/system/etc/boot-image.bprof")
- rule.Build(pctx, ctx, "bootFrameworkProfile", "profile boot framework jars")
+ rule.Build("bootFrameworkProfile", "profile boot framework jars")
image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
return profile
@@ -651,16 +853,10 @@ func updatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConf
updatableBcpPackagesName := "updatable-bcp-packages.txt"
updatableBcpPackages := image.dir.Join(ctx, updatableBcpPackagesName)
- ctx.Build(pctx, android.BuildParams{
- Rule: android.WriteFile,
- Output: updatableBcpPackages,
- Args: map[string]string{
- // WriteFile automatically adds the last end-of-line.
- "content": strings.Join(updatablePackages, "\\n"),
- },
- })
+ // WriteFileRule automatically adds the last end-of-line.
+ android.WriteFileRule(ctx, updatableBcpPackages, strings.Join(updatablePackages, "\n"))
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.MissingDeps(missingDeps)
rule.Install(updatableBcpPackages, "/system/etc/"+updatableBcpPackagesName)
// TODO: Rename `profileInstalls` to `extraInstalls`?
@@ -684,25 +880,25 @@ func dumpOatRules(ctx android.SingletonContext, image *bootImageConfig) {
}
// Create a rule to call oatdump.
output := android.PathForOutput(ctx, "boot."+suffix+".oatdump.txt")
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
// TODO: for now, use the debug version for better error reporting
- BuiltTool(ctx, "oatdumpd").
+ BuiltTool("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()).
FlagWithOutput("--output=", output).
FlagWithArg("--instruction-set=", arch.String())
- rule.Build(pctx, ctx, "dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
+ rule.Build("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-"+suffix)
- rule = android.NewRuleBuilder()
+ rule = android.NewRuleBuilder(pctx, ctx)
rule.Command().
Implicit(output).
ImplicitOutput(phony).
Text("echo").FlagWithArg("Output in ", output.String())
- rule.Build(pctx, ctx, "phony-dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
+ rule.Build("phony-dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
allPhonies = append(allPhonies, phony)
}
@@ -720,16 +916,12 @@ func dumpOatRules(ctx android.SingletonContext, image *bootImageConfig) {
func writeGlobalConfigForMake(ctx android.SingletonContext, path android.WritablePath) {
data := dexpreopt.GetGlobalConfigRawData(ctx)
- ctx.Build(pctx, android.BuildParams{
- Rule: android.WriteFile,
- Output: path,
- Args: map[string]string{
- "content": string(data),
- },
- })
+ android.WriteFileRule(ctx, path, string(data))
}
-// Export paths for default boot image to Make
+// Define Make variables for boot image names, paths, etc. These variables are used in makefiles
+// (make/core/dex_preopt_libart.mk) to generate install rules that copy boot image files to the
+// correct output directories.
func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) {
if d.dexpreoptConfigForMake != nil {
ctx.Strict("DEX_PREOPT_CONFIG_FOR_MAKE", d.dexpreoptConfigForMake.String())
@@ -743,6 +935,11 @@ func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) {
ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.getAnyAndroidVariant().dexLocationsDeps, " "))
var imageNames []string
+ // TODO: the primary ART boot image should not be exposed to Make, as it is installed in a
+ // different way as a part of the ART APEX. However, there is a special JIT-Zygote build
+ // configuration which uses the primary ART image instead of the Framework boot image
+ // extension, and it relies on the ART image being exposed to Make. To fix this, it is
+ // necessary to rework the logic in makefiles.
for _, current := range append(d.otherImages, image) {
imageNames = append(imageNames, current.name)
for _, variant := range current.variants {
diff --git a/java/droiddoc.go b/java/droiddoc.go
index c7a27c2a4..9c88a3ca2 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -671,7 +671,7 @@ func (j *Javadoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.stubsSrcJar = nil
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().Text("rm -rf").Text(outDir.String())
rule.Command().Text("mkdir -p").Text(outDir.String())
@@ -689,7 +689,7 @@ func (j *Javadoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Flag("-Xdoclint:none")
rule.Command().
- BuiltTool(ctx, "soong_zip").
+ BuiltTool("soong_zip").
Flag("-write_if_changed").
Flag("-d").
FlagWithOutput("-o ", j.docZip).
@@ -700,7 +700,7 @@ func (j *Javadoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
zipSyncCleanupCmd(rule, srcJarDir)
- rule.Build(pctx, ctx, "javadoc", "javadoc")
+ rule.Build("javadoc", "javadoc")
}
//
@@ -845,7 +845,7 @@ func javadocCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs andro
outDir, srcJarDir, srcJarList android.Path, sourcepaths android.Paths) *android.RuleBuilderCommand {
cmd := rule.Command().
- BuiltTool(ctx, "soong_javac_wrapper").Tool(config.JavadocCmd(ctx)).
+ BuiltTool("soong_javac_wrapper").Tool(config.JavadocCmd(ctx)).
Flag(config.JavacVmFlags).
FlagWithArg("-encoding ", "UTF-8").
FlagWithRspFileInputList("@", srcs).
@@ -914,7 +914,7 @@ func dokkaCmd(ctx android.ModuleContext, rule *android.RuleBuilder,
dokkaClasspath := append(bootclasspath.Paths(), classpath.Paths()...)
return rule.Command().
- BuiltTool(ctx, "dokka").
+ BuiltTool("dokka").
Flag(config.JavacVmFlags).
Flag(srcJarDir.String()).
FlagWithInputList("-classpath ", dokkaClasspath, ":").
@@ -934,7 +934,7 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
outDir := android.PathForModuleOut(ctx, "out")
srcJarDir := android.PathForModuleOut(ctx, "srcjars")
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
@@ -968,7 +968,7 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
rule.Command().
- BuiltTool(ctx, "soong_zip").
+ BuiltTool("soong_zip").
Flag("-write_if_changed").
Flag("-d").
FlagWithOutput("-o ", d.docZip).
@@ -979,7 +979,7 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
zipSyncCleanupCmd(rule, srcJarDir)
- rule.Build(pctx, ctx, "javadoc", desc)
+ rule.Build("javadoc", desc)
}
//
@@ -1050,7 +1050,8 @@ func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) {
return android.Paths{d.stubsSrcJar}, nil
case ".docs.zip":
return android.Paths{d.docZip}, nil
- case ".api.txt":
+ case ".api.txt", android.DefaultDistTag:
+ // This is the default dist path for dist properties that have no tag property.
return android.Paths{d.apiFilePath}, nil
case ".removed-api.txt":
return android.Paths{d.removedApiFilePath}, nil
@@ -1277,7 +1278,7 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi
}).NoVarTemplate(ctx.Config()))
}
- cmd.BuiltTool(ctx, "metalava").
+ cmd.BuiltTool("metalava").
Flag(config.JavacVmFlags).
Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED").
FlagWithArg("-encoding ", "UTF-8").
@@ -1332,7 +1333,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
srcJarDir := android.PathForModuleOut(ctx, "srcjars")
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
if BoolDefault(d.properties.High_mem, false) {
// This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel.
@@ -1479,19 +1480,19 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
cmd.FlagWithArg("--error-message:compatibility:released ", msg)
}
- impRule := android.NewRuleBuilder()
+ impRule := android.NewRuleBuilder(pctx, ctx)
impCmd := impRule.Command()
// 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.
impCmd.Text("cp").FlagWithRspFileInputList("", cmd.GetImplicits()).Output(implicitsRsp)
- impRule.Build(pctx, ctx, "implicitsGen", "implicits generation")
+ impRule.Build("implicitsGen", "implicits generation")
cmd.Implicit(implicitsRsp)
if generateStubs {
rule.Command().
- BuiltTool(ctx, "soong_zip").
+ BuiltTool("soong_zip").
Flag("-write_if_changed").
Flag("-jar").
FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
@@ -1502,7 +1503,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if Bool(d.properties.Write_sdk_values) {
d.metadataZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-metadata.zip")
rule.Command().
- BuiltTool(ctx, "soong_zip").
+ BuiltTool("soong_zip").
Flag("-write_if_changed").
Flag("-d").
FlagWithOutput("-o ", d.metadataZip).
@@ -1523,7 +1524,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
zipSyncCleanupCmd(rule, srcJarDir)
- rule.Build(pctx, ctx, "metalava", "metalava merged")
+ rule.Build("metalava", "metalava merged")
if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
@@ -1541,7 +1542,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp")
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
// Diff command line.
// -F matches the closest "opening" line, such as "package android {"
@@ -1563,7 +1564,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
` to the new methods, etc. shown in the above diff.\n\n`+
` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+
- ` make %s-update-current-api\n\n`+
+ ` m %s-update-current-api\n\n`+
` To submit the revised current.txt to the main Android repository,\n`+
` you will need approval.\n`+
`******************************\n`, ctx.ModuleName())
@@ -1575,12 +1576,12 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Text("; exit 38").
Text(")")
- rule.Build(pctx, ctx, "metalavaCurrentApiCheck", "check current API")
+ rule.Build("metalavaCurrentApiCheck", "check current API")
d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp")
// update API rule
- rule = android.NewRuleBuilder()
+ rule = android.NewRuleBuilder(pctx, ctx)
rule.Command().Text("( true")
@@ -1601,7 +1602,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Text("; exit 38").
Text(")")
- rule.Build(pctx, ctx, "metalavaCurrentApiUpdate", "update current API")
+ rule.Build("metalavaCurrentApiUpdate", "update current API")
}
if String(d.properties.Check_nullability_warnings) != "" {
@@ -1624,7 +1625,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
` and submitting the updated file as part of your change.`,
d.nullabilityWarningsFile, checkNullabilityWarnings)
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
Text("(").
@@ -1636,7 +1637,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Text("; exit 38").
Text(")")
- rule.Build(pctx, ctx, "nullabilityWarningsCheck", "nullability warnings check")
+ rule.Build("nullabilityWarningsCheck", "nullability warnings check")
}
}
@@ -1721,7 +1722,7 @@ func zipSyncCmd(ctx android.ModuleContext, rule *android.RuleBuilder,
rule.Temporary(srcJarList)
- rule.Command().BuiltTool(ctx, "zipsync").
+ rule.Command().BuiltTool("zipsync").
FlagWithArg("-d ", srcJarDir.String()).
FlagWithOutput("-l ", srcJarList).
FlagWithArg("-f ", `"*.java"`).
@@ -1748,8 +1749,6 @@ type PrebuiltStubsSources struct {
properties PrebuiltStubsSourcesProperties
- // The source directories containing stubs source files.
- srcDirs android.Paths
stubsSrcJar android.ModuleOutPath
}
@@ -1769,25 +1768,33 @@ func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
p.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
- p.srcDirs = android.PathsForModuleSrc(ctx, p.properties.Srcs)
+ if len(p.properties.Srcs) != 1 {
+ ctx.PropertyErrorf("srcs", "must only specify one directory path, contains %d paths", len(p.properties.Srcs))
+ return
+ }
+
+ localSrcDir := p.properties.Srcs[0]
+ // Although PathForModuleSrc can return nil if either the path doesn't exist or
+ // the path components are invalid it won't in this case because no components
+ // are specified and the module directory must exist in order to get this far.
+ srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, localSrcDir)
+
+ // Glob the contents of the directory just in case the directory does not exist.
+ srcGlob := localSrcDir + "/**/*"
+ srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
- rule := android.NewRuleBuilder()
- command := rule.Command().
- BuiltTool(ctx, "soong_zip").
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ BuiltTool("soong_zip").
Flag("-write_if_changed").
Flag("-jar").
- FlagWithOutput("-o ", p.stubsSrcJar)
-
- for _, d := range p.srcDirs {
- dir := d.String()
- command.
- FlagWithArg("-C ", dir).
- FlagWithInput("-D ", d)
- }
+ FlagWithOutput("-o ", p.stubsSrcJar).
+ FlagWithArg("-C ", srcDir.String()).
+ FlagWithRspFileInputList("-r ", srcPaths)
rule.Restat()
- rule.Build(pctx, ctx, "zip src", "Create srcjar from prebuilt source")
+ rule.Build("zip src", "Create srcjar from prebuilt source")
}
func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
diff --git a/java/gen.go b/java/gen.go
index d50a6653e..5766a9471 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -57,7 +57,7 @@ func genAidl(ctx android.ModuleContext, aidlFiles android.Paths, aidlFlags strin
outDir := srcJarFile.ReplaceExtension(ctx, "tmp")
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().Text("rm -rf").Flag(outDir.String())
rule.Command().Text("mkdir -p").Flag(outDir.String())
@@ -98,7 +98,7 @@ func genAidl(ctx android.ModuleContext, aidlFiles android.Paths, aidlFlags strin
ruleDesc += " " + strconv.Itoa(i)
}
- rule.Build(pctx, ctx, ruleName, ruleDesc)
+ rule.Build(ruleName, ruleDesc)
}
return srcJarFiles
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index 63b801a5c..71f1e576d 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -135,12 +135,12 @@ func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, flagsCSV, me
})
h.metadataCSVPath = metadataCSV
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
- BuiltTool(ctx, "merge_csv").
+ BuiltTool("merge_csv").
FlagWithInput("--zip_input=", classesJar).
FlagWithOutput("--output=", indexCSV)
- rule.Build(pctx, ctx, "merged-hiddenapi-index", "Merged Hidden API index")
+ rule.Build("merged-hiddenapi-index", "Merged Hidden API index")
h.indexCSVPath = indexCSV
}
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 1f80e777f..419dc3424 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -177,19 +177,20 @@ func stubFlagsRule(ctx android.SingletonContext) {
for moduleList, pathList := range moduleListToPathList {
for i := range pathList {
if pathList[i] == nil {
- pathList[i] = android.PathForOutput(ctx, "missing")
+ moduleName := (*moduleList)[i]
+ pathList[i] = android.PathForOutput(ctx, "missing/module", moduleName)
if ctx.Config().AllowMissingDependencies() {
- missingDeps = append(missingDeps, (*moduleList)[i])
+ missingDeps = append(missingDeps, moduleName)
} else {
ctx.Errorf("failed to find dex jar path for module %q",
- (*moduleList)[i])
+ moduleName)
}
}
}
}
// Singleton rule which applies hiddenapi on all boot class path dex files.
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
outputPath := hiddenAPISingletonPaths(ctx).stubFlags
tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp")
@@ -208,7 +209,7 @@ func stubFlagsRule(ctx android.SingletonContext) {
commitChangeForRestat(rule, tempPath, outputPath)
- rule.Build(pctx, ctx, "hiddenAPIStubFlagsFile", "hiddenapi stub flags")
+ rule.Build("hiddenAPIStubFlagsFile", "hiddenapi stub flags")
}
// flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and
@@ -236,7 +237,7 @@ func flagsRule(ctx android.SingletonContext) android.Path {
ctx.Errorf("Failed to find combined-removed-dex.")
}
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
outputPath := hiddenAPISingletonPaths(ctx).flags
tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp")
@@ -255,18 +256,18 @@ func flagsRule(ctx android.SingletonContext) android.Path {
FlagWithInput("--max-target-p ",
android.PathForSource(ctx, "frameworks/base/config/hiddenapi-max-target-p.txt")).
FlagWithInput("--max-target-o ", android.PathForSource(
- ctx, "frameworks/base/config/hiddenapi-max-target-o.txt")).Flag("--ignore-conflicts ").
+ ctx, "frameworks/base/config/hiddenapi-max-target-o.txt")).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio").
FlagWithInput("--blocked ",
android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blocked.txt")).
FlagWithInput("--blocked ",
- android.PathForSource(ctx, "frameworks/base/config/hiddenapi-temp-blocklist.txt")).
+ android.PathForSource(ctx, "frameworks/base/config/hiddenapi-temp-blocklist.txt")).FlagWithArg("--tag ", "lo-prio").
FlagWithInput("--unsupported ", android.PathForSource(
ctx, "frameworks/base/config/hiddenapi-unsupported-packages.txt")).Flag("--packages ").
FlagWithOutput("--output ", tempPath)
commitChangeForRestat(rule, tempPath, outputPath)
- rule.Build(pctx, ctx, "hiddenAPIFlagsFile", "hiddenapi flags")
+ rule.Build("hiddenAPIFlagsFile", "hiddenapi flags")
return outputPath
}
@@ -274,14 +275,14 @@ func flagsRule(ctx android.SingletonContext) android.Path {
// emptyFlagsRule creates a rule to build an empty hiddenapi-flags.csv, which is needed by master-art-host builds that
// have a partial manifest without frameworks/base but still need to build a boot image.
func emptyFlagsRule(ctx android.SingletonContext) android.Path {
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
outputPath := hiddenAPISingletonPaths(ctx).flags
rule.Command().Text("rm").Flag("-f").Output(outputPath)
rule.Command().Text("touch").Output(outputPath)
- rule.Build(pctx, ctx, "emptyHiddenAPIFlagsFile", "empty hiddenapi flags")
+ rule.Build("emptyHiddenAPIFlagsFile", "empty hiddenapi flags")
return outputPath
}
@@ -299,16 +300,16 @@ func metadataRule(ctx android.SingletonContext) android.Path {
}
})
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
outputPath := hiddenAPISingletonPaths(ctx).metadata
rule.Command().
- BuiltTool(ctx, "merge_csv").
+ BuiltTool("merge_csv").
FlagWithOutput("--output=", outputPath).
Inputs(metadataCSV)
- rule.Build(pctx, ctx, "hiddenAPIGreylistMetadataFile", "hiddenapi greylist metadata")
+ rule.Build("hiddenAPIGreylistMetadataFile", "hiddenapi greylist metadata")
return outputPath
}
@@ -399,13 +400,13 @@ func (h *hiddenAPIIndexSingleton) GenerateBuildActions(ctx android.SingletonCont
}
})
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
- BuiltTool(ctx, "merge_csv").
+ BuiltTool("merge_csv").
FlagWithArg("--header=", "signature,file,startline,startcol,endline,endcol,properties").
FlagWithOutput("--output=", hiddenAPISingletonPaths(ctx).index).
Inputs(indexes)
- rule.Build(pctx, ctx, "singleton-merged-hiddenapi-index", "Singleton merged Hidden API index")
+ rule.Build("singleton-merged-hiddenapi-index", "Singleton merged Hidden API index")
h.index = hiddenAPISingletonPaths(ctx).index
}
diff --git a/java/java.go b/java/java.go
index d6dc148a6..d44719e99 100644
--- a/java/java.go
+++ b/java/java.go
@@ -201,7 +201,10 @@ type CompilerProperties struct {
// List of modules to use as annotation processors
Plugins []string
- // List of modules to export to libraries that directly depend on this library as annotation processors
+ // List of modules to export to libraries that directly depend on this library as annotation
+ // processors. Note that if the plugins set generates_api: true this will disable the turbine
+ // optimization on modules that depend on this module, which will reduce parallelism and cause
+ // more recompilation.
Exported_plugins []string
// The number of Java source entries each Javac instance can process
@@ -248,6 +251,9 @@ type CompilerProperties struct {
Errorprone struct {
// List of javac flags that should only be used when running errorprone.
Javacflags []string
+
+ // List of java_plugin modules that provide extra errorprone checks.
+ Extra_check_modules []string
}
Proto struct {
@@ -417,7 +423,7 @@ type Module struct {
overrideManifest android.OptionalPath
// map of SDK version to class loader context
- exportedSdkLibs dexpreopt.ClassLoaderContextMap
+ classLoaderContexts dexpreopt.ClassLoaderContextMap
// list of plugins that this java module is exporting
exportedPluginJars android.Paths
@@ -425,6 +431,9 @@ type Module struct {
// list of plugins that this java module is exporting
exportedPluginClasses []string
+ // if true, the exported plugins generate API and require disabling turbine.
+ exportedDisableTurbine bool
+
// list of source files, collected from srcFiles with unique java and all kt files,
// will be used by android.IDEInfo struct
expandIDEInfoCompiledSrcs []string
@@ -447,8 +456,6 @@ type Module struct {
// list of the xref extraction files
kytheFiles android.Paths
- distFiles android.TaggedDistFiles
-
// Collect the module directory for IDE info in java/jdeps.go.
modulePaths []string
@@ -477,6 +484,8 @@ func (j *Module) OutputFiles(tag string) (android.Paths, error) {
switch tag {
case "":
return append(android.Paths{j.outputFile}, j.extraOutputFiles...), nil
+ case android.DefaultDistTag:
+ return android.Paths{j.outputFile}, nil
case ".jar":
return android.Paths{j.implementationAndResourcesJar}, nil
case ".proguard_map":
@@ -509,8 +518,8 @@ type Dependency interface {
ImplementationJars() android.Paths
ResourceJars() android.Paths
AidlIncludeDirs() android.Paths
- ExportedSdkLibs() dexpreopt.ClassLoaderContextMap
- ExportedPlugins() (android.Paths, []string)
+ ClassLoaderContexts() dexpreopt.ClassLoaderContextMap
+ ExportedPlugins() (android.Paths, []string, bool)
SrcJarArgs() ([]string, android.Paths)
BaseModuleName() string
JacocoReportClassesFile() android.Path
@@ -547,6 +556,14 @@ type dependencyTag struct {
name string
}
+// installDependencyTag is a dependency tag that is annotated to cause the installed files of the
+// dependency to be installed when the parent module is installed.
+type installDependencyTag struct {
+ blueprint.BaseDependencyTag
+ android.InstallAlwaysNeededDependencyTag
+ name string
+}
+
type usesLibraryDependencyTag struct {
dependencyTag
sdkVersion int // SDK version in which the library appared as a standalone library.
@@ -569,6 +586,7 @@ var (
libTag = dependencyTag{name: "javalib"}
java9LibTag = dependencyTag{name: "java9lib"}
pluginTag = dependencyTag{name: "plugin"}
+ errorpronePluginTag = dependencyTag{name: "errorprone-plugin"}
exportedPluginTag = dependencyTag{name: "exported-plugin"}
bootClasspathTag = dependencyTag{name: "bootclasspath"}
systemModulesTag = dependencyTag{name: "system modules"}
@@ -580,6 +598,8 @@ var (
instrumentationForTag = dependencyTag{name: "instrumentation_for"}
extraLintCheckTag = dependencyTag{name: "extra-lint-check"}
jniLibTag = dependencyTag{name: "jnilib"}
+ jniInstallTag = installDependencyTag{name: "jni install"}
+ binaryInstallTag = installDependencyTag{name: "binary install"}
usesLibTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion)
usesLibCompat28Tag = makeUsesLibraryDependencyTag(28)
usesLibCompat29Tag = makeUsesLibraryDependencyTag(29)
@@ -752,6 +772,37 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) {
libDeps := ctx.AddVariationDependencies(nil, libTag, rewriteSyspropLibs(j.properties.Libs, "libs")...)
ctx.AddVariationDependencies(nil, staticLibTag, rewriteSyspropLibs(j.properties.Static_libs, "static_libs")...)
+ if ctx.DeviceConfig().VndkVersion() != "" && ctx.Config().EnforceInterPartitionJavaSdkLibrary() {
+ // Require java_sdk_library at inter-partition java dependency to ensure stable
+ // interface between partitions. If inter-partition java_library dependency is detected,
+ // raise build error because java_library doesn't have a stable interface.
+ //
+ // Inputs:
+ // PRODUCT_ENFORCE_INTER_PARTITION_JAVA_SDK_LIBRARY
+ // if true, enable enforcement
+ // PRODUCT_INTER_PARTITION_JAVA_LIBRARY_ALLOWLIST
+ // exception list of java_library names to allow inter-partition dependency
+ for idx, lib := range j.properties.Libs {
+ if libDeps[idx] == nil {
+ continue
+ }
+
+ if _, ok := syspropPublicStubs[lib]; ok {
+ continue
+ }
+
+ if javaDep, ok := libDeps[idx].(javaSdkLibraryEnforceContext); ok {
+ // java_sdk_library is always allowed at inter-partition dependency.
+ // So, skip check.
+ if _, ok := javaDep.(*SdkLibrary); ok {
+ continue
+ }
+
+ j.checkPartitionsForJavaDependency(ctx, "libs", javaDep)
+ }
+ }
+ }
+
// For library dependencies that are component libraries (like stubs), add the implementation
// as a dependency (dexpreopt needs to be against the implementation library, not stubs).
for _, dep := range libDeps {
@@ -765,6 +816,7 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) {
}
ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), pluginTag, j.properties.Plugins...)
+ ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), errorpronePluginTag, j.properties.Errorprone.Extra_check_modules...)
ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), exportedPluginTag, j.properties.Exported_plugins...)
android.ProtoDeps(ctx, &j.protoProperties)
@@ -852,21 +904,22 @@ func (j *Module) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.Opt
}
type deps struct {
- classpath classpath
- java9Classpath classpath
- bootClasspath classpath
- processorPath classpath
- processorClasses []string
- staticJars android.Paths
- staticHeaderJars android.Paths
- staticResourceJars android.Paths
- aidlIncludeDirs android.Paths
- srcs android.Paths
- srcJars android.Paths
- systemModules *systemModules
- aidlPreprocess android.OptionalPath
- kotlinStdlib android.Paths
- kotlinAnnotations android.Paths
+ classpath classpath
+ java9Classpath classpath
+ bootClasspath classpath
+ processorPath classpath
+ errorProneProcessorPath classpath
+ processorClasses []string
+ staticJars android.Paths
+ staticHeaderJars android.Paths
+ staticResourceJars android.Paths
+ aidlIncludeDirs android.Paths
+ srcs android.Paths
+ srcJars android.Paths
+ systemModules *systemModules
+ aidlPreprocess android.OptionalPath
+ kotlinStdlib android.Paths
+ kotlinAnnotations android.Paths
disableTurbine bool
}
@@ -952,7 +1005,9 @@ func checkLinkType(ctx android.ModuleContext, from *Module, to linkTypeContext,
return
}
otherLinkType, _ := to.getLinkType(ctx.OtherModuleName(to))
- commonMessage := "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source."
+ commonMessage := " In order to fix this, consider adjusting sdk_version: OR platform_apis: " +
+ "property of the source or target module so that target module is built with the same " +
+ "or smaller API set when compared to the source."
switch myLinkType {
case javaCore:
@@ -1026,8 +1081,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
switch tag {
case libTag:
deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
- // names of sdk libs that are directly depended are exported
- j.exportedSdkLibs.MaybeAddContext(ctx, dep.OptionalImplicitSdkLibrary(),
+ j.classLoaderContexts.MaybeAddContext(ctx, dep.OptionalImplicitSdkLibrary(),
dep.DexJarBuildPath(), dep.DexJarInstallPath())
case staticLibTag:
ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
@@ -1038,11 +1092,11 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars()...)
case libTag, instrumentationForTag:
deps.classpath = append(deps.classpath, dep.HeaderJars()...)
- // sdk lib names from dependencies are re-exported
- j.exportedSdkLibs.AddContextMap(dep.ExportedSdkLibs(), otherName)
+ j.classLoaderContexts.AddContextMap(dep.ClassLoaderContexts(), otherName)
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
- pluginJars, pluginClasses := dep.ExportedPlugins()
+ pluginJars, pluginClasses, disableTurbine := dep.ExportedPlugins()
addPlugins(&deps, pluginJars, pluginClasses...)
+ deps.disableTurbine = deps.disableTurbine || disableTurbine
case java9LibTag:
deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars()...)
case staticLibTag:
@@ -1050,11 +1104,13 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
deps.staticJars = append(deps.staticJars, dep.ImplementationJars()...)
deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...)
deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars()...)
- // sdk lib names from dependencies are re-exported
- j.exportedSdkLibs.AddContextMap(dep.ExportedSdkLibs(), otherName)
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
- pluginJars, pluginClasses := dep.ExportedPlugins()
+ pluginJars, pluginClasses, disableTurbine := dep.ExportedPlugins()
addPlugins(&deps, pluginJars, pluginClasses...)
+ // Turbine doesn't run annotation processors, so any module that uses an
+ // annotation processor that generates API is incompatible with the turbine
+ // optimization.
+ deps.disableTurbine = deps.disableTurbine || disableTurbine
case pluginTag:
if plugin, ok := dep.(*Plugin); ok {
if plugin.pluginProperties.Processor_class != nil {
@@ -1062,19 +1118,29 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
} else {
addPlugins(&deps, plugin.ImplementationAndResourcesJars())
}
+ // Turbine doesn't run annotation processors, so any module that uses an
+ // annotation processor that generates API is incompatible with the turbine
+ // optimization.
deps.disableTurbine = deps.disableTurbine || Bool(plugin.pluginProperties.Generates_api)
} else {
ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName)
}
+ case errorpronePluginTag:
+ if plugin, ok := dep.(*Plugin); ok {
+ deps.errorProneProcessorPath = append(deps.errorProneProcessorPath, plugin.ImplementationAndResourcesJars()...)
+ } else {
+ ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName)
+ }
case exportedPluginTag:
if plugin, ok := dep.(*Plugin); ok {
- if plugin.pluginProperties.Generates_api != nil && *plugin.pluginProperties.Generates_api {
- ctx.PropertyErrorf("exported_plugins", "Cannot export plugins with generates_api = true, found %v", otherName)
- }
j.exportedPluginJars = append(j.exportedPluginJars, plugin.ImplementationAndResourcesJars()...)
if plugin.pluginProperties.Processor_class != nil {
j.exportedPluginClasses = append(j.exportedPluginClasses, *plugin.pluginProperties.Processor_class)
}
+ // Turbine doesn't run annotation processors, so any module that uses an
+ // annotation processor that generates API is incompatible with the turbine
+ // optimization.
+ j.exportedDisableTurbine = Bool(plugin.pluginProperties.Generates_api)
} else {
ctx.PropertyErrorf("exported_plugins", "%q is not a java_plugin module", otherName)
}
@@ -1112,6 +1178,9 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
deps.systemModules = &systemModules{outputDir, outputDeps}
}
}
+
+ // Merge dep's CLC after processing the dep itself (which may add its own <uses-library>).
+ maybeAddCLCFromDep(module, tag, otherName, j.classLoaderContexts)
})
return deps
@@ -1189,7 +1258,7 @@ func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaB
flags.javaVersion = getJavaVersion(ctx, String(j.properties.Java_version), sdkContext(j))
if ctx.Config().RunErrorProne() {
- if config.ErrorProneClasspath == nil {
+ if config.ErrorProneClasspath == nil && ctx.Config().TestProductVariables == nil {
ctx.ModuleErrorf("cannot build with Error Prone, missing external/error_prone?")
}
@@ -1209,6 +1278,7 @@ func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaB
flags.classpath = append(flags.classpath, deps.classpath...)
flags.java9Classpath = append(flags.java9Classpath, deps.java9Classpath...)
flags.processorPath = append(flags.processorPath, deps.processorPath...)
+ flags.errorProneProcessorPath = append(flags.errorProneProcessorPath, deps.errorProneProcessorPath...)
flags.processors = append(flags.processors, deps.processorClasses...)
flags.processors = android.FirstUniqueStrings(flags.processors)
@@ -1375,6 +1445,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
kotlincFlags := j.properties.Kotlincflags
CheckKotlincFlags(ctx, kotlincFlags)
+ // Dogfood the JVM_IR backend.
+ kotlincFlags = append(kotlincFlags, "-Xuse-ir")
+
// If there are kotlin files, compile them first but pass all the kotlin and java files
// kotlinc will use the java files to resolve types referenced by the kotlin files, but
// won't emit any classes for them.
@@ -1903,12 +1976,15 @@ func (j *Module) AidlIncludeDirs() android.Paths {
return j.exportAidlIncludeDirs
}
-func (j *Module) ExportedSdkLibs() dexpreopt.ClassLoaderContextMap {
- return j.exportedSdkLibs
+func (j *Module) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap {
+ return j.classLoaderContexts
}
-func (j *Module) ExportedPlugins() (android.Paths, []string) {
- return j.exportedPluginJars, j.exportedPluginClasses
+// ExportedPlugins returns the list of jars needed to run the exported plugins, the list of
+// classes for the plugins, and a boolean for whether turbine needs to be disabled due to plugins
+// that generate APIs.
+func (j *Module) ExportedPlugins() (android.Paths, []string, bool) {
+ return j.exportedPluginJars, j.exportedPluginClasses, j.exportedDisableTurbine
}
func (j *Module) SrcJarArgs() ([]string, android.Paths) {
@@ -2042,7 +2118,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter))
}
j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
- j.exportedSdkLibs = make(dexpreopt.ClassLoaderContextMap)
+ j.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap)
j.compile(ctx, nil)
// Collect the module directory for IDE info in java/jdeps.go.
@@ -2062,15 +2138,13 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// 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.MaybeAddContext(ctx, j.OptionalImplicitSdkLibrary(),
+ j.classLoaderContexts.MaybeAddContext(ctx, j.OptionalImplicitSdkLibrary(),
j.DexJarBuildPath(), j.DexJarInstallPath())
// A non-SDK library may provide a <uses-library> (the name may be different from the module name).
if lib := proptools.String(j.usesLibraryProperties.Provides_uses_lib); lib != "" {
- j.exportedSdkLibs.AddContext(ctx, lib, j.DexJarBuildPath(), j.DexJarInstallPath())
+ j.classLoaderContexts.AddContext(ctx, lib, j.DexJarBuildPath(), j.DexJarInstallPath())
}
-
- j.distFiles = j.GenerateTaggedDistFiles(ctx)
}
func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -2226,6 +2300,9 @@ func LibraryHostFactory() android.Module {
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"`
+
+ // If the test is a hostside(no device required) unittest that shall be run during presubmit check.
+ Unit_test *bool
}
type testProperties struct {
@@ -2322,7 +2399,7 @@ func (j *TestHost) DepsMutator(ctx android.BottomUpMutatorContext) {
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.testProperties.Test_suites, j.testProperties.Auto_gen_config, j.testProperties.Test_options.Unit_test)
j.data = android.PathsForModuleSrc(ctx, j.testProperties.Data)
@@ -2341,7 +2418,7 @@ func (j *TestHelperLibrary) GenerateAndroidBuildActions(ctx android.ModuleContex
func (j *JavaTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.prebuiltTestProperties.Test_config, nil,
- j.prebuiltTestProperties.Test_suites, nil)
+ j.prebuiltTestProperties.Test_suites, nil, nil)
j.Import.GenerateAndroidBuildActions(ctx)
}
@@ -2550,9 +2627,12 @@ func (j *Binary) DepsMutator(ctx android.BottomUpMutatorContext) {
if ctx.Arch().ArchType == android.Common {
j.deps(ctx)
} else {
- // This dependency ensures the host installation rules will install the jni libraries
- // when the wrapper is installed.
- ctx.AddVariationDependencies(nil, jniLibTag, j.binaryProperties.Jni_libs...)
+ // These dependencies ensure the host installation rules will install the jar file and
+ // the jni libraries when the wrapper is installed.
+ ctx.AddVariationDependencies(nil, jniInstallTag, j.binaryProperties.Jni_libs...)
+ ctx.AddVariationDependencies(
+ []blueprint.Variation{{Mutator: "arch", Variation: android.CommonArch.String()}},
+ binaryInstallTag, ctx.ModuleName())
}
}
@@ -2646,7 +2726,7 @@ type Import struct {
dexJarFile android.Path
combinedClasspathFile android.Path
- exportedSdkLibs dexpreopt.ClassLoaderContextMap
+ classLoaderContexts dexpreopt.ClassLoaderContextMap
exportAidlIncludeDirs android.Paths
hideApexVariantFromMake bool
@@ -2721,7 +2801,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
TransformJetifier(ctx, outputFile, inputFile)
}
j.combinedClasspathFile = outputFile
- j.exportedSdkLibs = make(dexpreopt.ClassLoaderContextMap)
+ j.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap)
var flags javaBuilderFlags
@@ -2734,8 +2814,6 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
switch tag {
case libTag, staticLibTag:
flags.classpath = append(flags.classpath, dep.HeaderJars()...)
- // sdk lib names from dependencies are re-exported
- j.exportedSdkLibs.AddContextMap(dep.ExportedSdkLibs(), otherName)
case bootClasspathTag:
flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars()...)
}
@@ -2743,11 +2821,12 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
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.AddContext(ctx, otherName,
- dep.DexJarBuildPath(), dep.DexJarInstallPath())
+ j.classLoaderContexts.AddContext(ctx, otherName, dep.DexJarBuildPath(), dep.DexJarInstallPath())
}
}
+
+ // Merge dep's CLC after processing the dep itself (which may add its own <uses-library>).
+ maybeAddCLCFromDep(module, tag, otherName, j.classLoaderContexts)
})
var installFile android.Path
@@ -2760,7 +2839,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// 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.MaybeAddContext(ctx, j.OptionalImplicitSdkLibrary(),
+ j.classLoaderContexts.MaybeAddContext(ctx, j.OptionalImplicitSdkLibrary(),
outputFile, installFile)
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
@@ -2843,12 +2922,12 @@ func (j *Import) AidlIncludeDirs() android.Paths {
return j.exportAidlIncludeDirs
}
-func (j *Import) ExportedSdkLibs() dexpreopt.ClassLoaderContextMap {
- return j.exportedSdkLibs
+func (j *Import) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap {
+ return j.classLoaderContexts
}
-func (j *Import) ExportedPlugins() (android.Paths, []string) {
- return nil, nil
+func (j *Import) ExportedPlugins() (android.Paths, []string, bool) {
+ return nil, nil, false
}
func (j *Import) SrcJarArgs() ([]string, android.Paths) {
@@ -3003,21 +3082,21 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
dexOutputFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".jar")
if j.dexpreopter.uncompressedDex {
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
temporary := android.PathForModuleOut(ctx, ctx.ModuleName()+".jar.unaligned")
rule.Temporary(temporary)
// use zip2zip to uncompress classes*.dex files
rule.Command().
- BuiltTool(ctx, "zip2zip").
+ BuiltTool("zip2zip").
FlagWithInput("-i ", inputJar).
FlagWithOutput("-o ", temporary).
FlagWithArg("-0 ", "'classes*.dex'")
// use zipalign to align uncompressed classes*.dex files
rule.Command().
- BuiltTool(ctx, "zipalign").
+ BuiltTool("zipalign").
Flag("-f").
Text("4").
Input(temporary).
@@ -3025,7 +3104,7 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
rule.DeleteTemporaryFiles()
- rule.Build(pctx, ctx, "uncompress_dex", "uncompress dex")
+ rule.Build("uncompress_dex", "uncompress dex")
} else {
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
@@ -3168,3 +3247,31 @@ var Bool = proptools.Bool
var BoolDefault = proptools.BoolDefault
var String = proptools.String
var inList = android.InList
+
+// Add class loader context of a given dependency to the given class loader context, provided that
+// all the necessary conditions are met.
+func maybeAddCLCFromDep(depModule android.Module, depTag blueprint.DependencyTag,
+ depName string, clcMap dexpreopt.ClassLoaderContextMap) {
+
+ if dep, ok := depModule.(Dependency); ok {
+ if depTag == libTag {
+ // Ok, propagate <uses-library> through non-static library dependencies.
+ } else if depTag == staticLibTag {
+ // Propagate <uses-library> through static library dependencies, unless it is a
+ // component library (such as stubs). Component libraries have a dependency on their
+ // SDK library, which should not be pulled just because of a static component library.
+ if comp, isComp := depModule.(SdkLibraryComponentDependency); isComp {
+ if compName := comp.OptionalImplicitSdkLibrary(); compName != nil {
+ dep = nil
+ }
+ }
+ } else {
+ // Don't propagate <uses-library> for other dependency tags.
+ dep = nil
+ }
+
+ if dep != nil {
+ clcMap.AddContextMap(dep.ClassLoaderContexts(), depName)
+ }
+ }
+}
diff --git a/java/java_test.go b/java/java_test.go
index 4594b8111..f7cf03f4d 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -15,6 +15,7 @@
package java
import (
+ "fmt"
"io/ioutil"
"os"
"path/filepath"
@@ -29,7 +30,6 @@ import (
"android/soong/android"
"android/soong/cc"
"android/soong/dexpreopt"
- "android/soong/genrule"
"android/soong/python"
)
@@ -80,7 +80,6 @@ func testContext(config android.Config) *android.TestContext {
RegisterSystemModulesBuildComponents(ctx)
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)
@@ -92,8 +91,8 @@ func testContext(config android.Config) *android.TestContext {
ctx.PreDepsMutators(python.RegisterPythonPreDepsMutators)
ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
- ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory))
- ctx.RegisterPreSingletonType("sdk_versions", android.SingletonFactoryAdaptor(sdkPreSingletonFactory))
+ ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(ctx.Context, OverlaySingletonFactory))
+ ctx.RegisterPreSingletonType("sdk_versions", android.SingletonFactoryAdaptor(ctx.Context, sdkPreSingletonFactory))
android.RegisterPrebuiltMutators(ctx)
@@ -202,7 +201,7 @@ func TestJavaLinkType(t *testing.T) {
}
`)
- testJavaError(t, "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.", `
+ testJavaError(t, "consider adjusting sdk_version: OR platform_apis:", `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -246,7 +245,7 @@ func TestJavaLinkType(t *testing.T) {
}
`)
- testJavaError(t, "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.", `
+ testJavaError(t, "consider adjusting sdk_version: OR platform_apis:", `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -314,8 +313,9 @@ func TestSimple(t *testing.T) {
func TestExportedPlugins(t *testing.T) {
type Result struct {
- library string
- processors string
+ library string
+ processors string
+ disableTurbine bool
}
var tests = []struct {
name string
@@ -374,6 +374,18 @@ func TestExportedPlugins(t *testing.T) {
{library: "foo", processors: "-processor com.android.TestPlugin,com.android.TestPlugin2"},
},
},
+ {
+ name: "Exports plugin to with generates_api to dependee",
+ extra: `
+ java_library{name: "exports", exported_plugins: ["plugin_generates_api"]}
+ java_library{name: "foo", srcs: ["a.java"], libs: ["exports"]}
+ java_library{name: "bar", srcs: ["a.java"], static_libs: ["exports"]}
+ `,
+ results: []Result{
+ {library: "foo", processors: "-processor com.android.TestPlugin", disableTurbine: true},
+ {library: "bar", processors: "-processor com.android.TestPlugin", disableTurbine: true},
+ },
+ },
}
for _, test := range tests {
@@ -383,6 +395,11 @@ func TestExportedPlugins(t *testing.T) {
name: "plugin",
processor_class: "com.android.TestPlugin",
}
+ java_plugin {
+ name: "plugin_generates_api",
+ generates_api: true,
+ processor_class: "com.android.TestPlugin",
+ }
`+test.extra)
for _, want := range test.results {
@@ -390,6 +407,11 @@ func TestExportedPlugins(t *testing.T) {
if javac.Args["processor"] != want.processors {
t.Errorf("For library %v, expected %v, found %v", want.library, want.processors, javac.Args["processor"])
}
+ turbine := ctx.ModuleForTests(want.library, "android_common").MaybeRule("turbine")
+ disableTurbine := turbine.BuildParams.Rule == nil
+ if disableTurbine != want.disableTurbine {
+ t.Errorf("For library %v, expected disableTurbine %v, found %v", want.library, want.disableTurbine, disableTurbine)
+ }
}
})
}
@@ -622,6 +644,35 @@ func assertDeepEquals(t *testing.T, message string, expected interface{}, actual
}
}
+func TestPrebuiltStubsSources(t *testing.T) {
+ test := func(t *testing.T, sourcesPath string, expectedInputs []string) {
+ ctx, _ := testJavaWithFS(t, fmt.Sprintf(`
+prebuilt_stubs_sources {
+ name: "stubs-source",
+ srcs: ["%s"],
+}`, sourcesPath), map[string][]byte{
+ "stubs/sources/pkg/A.java": nil,
+ "stubs/sources/pkg/B.java": nil,
+ })
+
+ zipSrc := ctx.ModuleForTests("stubs-source", "android_common").Rule("zip_src")
+ if expected, actual := expectedInputs, zipSrc.Inputs.Strings(); !reflect.DeepEqual(expected, actual) {
+ t.Errorf("mismatch of inputs to soong_zip: expected %q, actual %q", expected, actual)
+ }
+ }
+
+ t.Run("empty/missing directory", func(t *testing.T) {
+ test(t, "empty-directory", []string{})
+ })
+
+ t.Run("non-empty set of sources", func(t *testing.T) {
+ test(t, "stubs/sources", []string{
+ "stubs/sources/pkg/A.java",
+ "stubs/sources/pkg/B.java",
+ })
+ })
+}
+
func TestJavaSdkLibraryImport(t *testing.T) {
ctx, _ := testJava(t, `
java_library {
@@ -754,6 +805,165 @@ func TestJavaSdkLibraryImport_Preferred(t *testing.T) {
})
}
+func TestJavaSdkLibraryEnforce(t *testing.T) {
+ partitionToBpOption := func(partition string) string {
+ switch partition {
+ case "system":
+ return ""
+ case "vendor":
+ return "soc_specific: true,"
+ case "product":
+ return "product_specific: true,"
+ default:
+ panic("Invalid partition group name: " + partition)
+ }
+ }
+
+ type testConfigInfo struct {
+ libraryType string
+ fromPartition string
+ toPartition string
+ enforceVendorInterface bool
+ enforceProductInterface bool
+ enforceJavaSdkLibraryCheck bool
+ allowList []string
+ }
+
+ createTestConfig := func(info testConfigInfo) android.Config {
+ bpFileTemplate := `
+ java_library {
+ name: "foo",
+ srcs: ["foo.java"],
+ libs: ["bar"],
+ sdk_version: "current",
+ %s
+ }
+
+ %s {
+ name: "bar",
+ srcs: ["bar.java"],
+ sdk_version: "current",
+ %s
+ }
+ `
+
+ bpFile := fmt.Sprintf(bpFileTemplate,
+ partitionToBpOption(info.fromPartition),
+ info.libraryType,
+ partitionToBpOption(info.toPartition))
+
+ config := testConfig(nil, bpFile, nil)
+ configVariables := config.TestProductVariables
+
+ configVariables.EnforceProductPartitionInterface = proptools.BoolPtr(info.enforceProductInterface)
+ if info.enforceVendorInterface {
+ configVariables.DeviceVndkVersion = proptools.StringPtr("current")
+ }
+ configVariables.EnforceInterPartitionJavaSdkLibrary = proptools.BoolPtr(info.enforceJavaSdkLibraryCheck)
+ configVariables.InterPartitionJavaLibraryAllowList = info.allowList
+
+ return config
+ }
+
+ isValidDependency := func(configInfo testConfigInfo) bool {
+ if configInfo.enforceVendorInterface == false {
+ return true
+ }
+
+ if configInfo.enforceJavaSdkLibraryCheck == false {
+ return true
+ }
+
+ if inList("bar", configInfo.allowList) {
+ return true
+ }
+
+ if configInfo.libraryType == "java_library" {
+ if configInfo.fromPartition != configInfo.toPartition {
+ if !configInfo.enforceProductInterface &&
+ ((configInfo.fromPartition == "system" && configInfo.toPartition == "product") ||
+ (configInfo.fromPartition == "product" && configInfo.toPartition == "system")) {
+ return true
+ }
+ return false
+ }
+ }
+
+ return true
+ }
+
+ errorMessage := "is not allowed across the partitions"
+
+ allPartitionCombinations := func() [][2]string {
+ var result [][2]string
+ partitions := []string{"system", "vendor", "product"}
+
+ for _, fromPartition := range partitions {
+ for _, toPartition := range partitions {
+ result = append(result, [2]string{fromPartition, toPartition})
+ }
+ }
+
+ return result
+ }
+
+ allFlagCombinations := func() [][3]bool {
+ var result [][3]bool
+ flagValues := [2]bool{false, true}
+
+ for _, vendorInterface := range flagValues {
+ for _, productInterface := range flagValues {
+ for _, enableEnforce := range flagValues {
+ result = append(result, [3]bool{vendorInterface, productInterface, enableEnforce})
+ }
+ }
+ }
+
+ return result
+ }
+
+ for _, libraryType := range []string{"java_library", "java_sdk_library"} {
+ for _, partitionValues := range allPartitionCombinations() {
+ for _, flagValues := range allFlagCombinations() {
+ testInfo := testConfigInfo{
+ libraryType: libraryType,
+ fromPartition: partitionValues[0],
+ toPartition: partitionValues[1],
+ enforceVendorInterface: flagValues[0],
+ enforceProductInterface: flagValues[1],
+ enforceJavaSdkLibraryCheck: flagValues[2],
+ }
+
+ if isValidDependency(testInfo) {
+ testJavaWithConfig(t, createTestConfig(testInfo))
+ } else {
+ testJavaErrorWithConfig(t, errorMessage, createTestConfig(testInfo))
+ }
+ }
+ }
+ }
+
+ testJavaWithConfig(t, createTestConfig(testConfigInfo{
+ libraryType: "java_library",
+ fromPartition: "vendor",
+ toPartition: "system",
+ enforceVendorInterface: true,
+ enforceProductInterface: true,
+ enforceJavaSdkLibraryCheck: true,
+ allowList: []string{"bar"},
+ }))
+
+ testJavaErrorWithConfig(t, errorMessage, createTestConfig(testConfigInfo{
+ libraryType: "java_library",
+ fromPartition: "vendor",
+ toPartition: "system",
+ enforceVendorInterface: true,
+ enforceProductInterface: true,
+ enforceJavaSdkLibraryCheck: true,
+ allowList: []string{"foo"},
+ }))
+}
+
func TestDefaults(t *testing.T) {
ctx, _ := testJava(t, `
java_defaults {
@@ -1379,8 +1589,8 @@ func TestJarGenrules(t *testing.T) {
baz := ctx.ModuleForTests("baz", "android_common").Output("javac/baz.jar")
barCombined := ctx.ModuleForTests("bar", "android_common").Output("combined/bar.jar")
- if len(jargen.Inputs) != 1 || jargen.Inputs[0].String() != foo.Output.String() {
- t.Errorf("expected jargen inputs [%q], got %q", foo.Output.String(), jargen.Inputs.Strings())
+ if g, w := jargen.Implicits.Strings(), foo.Output.String(); !android.InList(w, g) {
+ t.Errorf("expected jargen inputs [%q], got %q", w, g)
}
if !strings.Contains(bar.Args["classpath"], jargen.Output.String()) {
@@ -1593,7 +1803,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().UsesLibs()
+ sdkLibs := quxLib.ClassLoaderContexts().UsesLibs()
if w := []string{"foo", "bar", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) {
t.Errorf("qux should export %q but exports %q", w, sdkLibs)
}
diff --git a/java/kotlin.go b/java/kotlin.go
index e8c030aa7..8067ad521 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -63,9 +63,9 @@ func kotlinCommonSrcsList(ctx android.ModuleContext, commonSrcFiles android.Path
// 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 := android.NewRuleBuilder(pctx, ctx)
rule.Command().Text("cp").FlagWithRspFileInputList("", commonSrcFiles).Output(commonSrcsList)
- rule.Build(pctx, ctx, "kotlin_common_srcs_list", "kotlin common_srcs list")
+ rule.Build("kotlin_common_srcs_list", "kotlin common_srcs list")
return android.OptionalPathForPath(commonSrcsList)
}
return android.OptionalPath{}
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index 60ca1c476..77ef29456 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -84,11 +84,14 @@ func TestKotlin(t *testing.T) {
}
func TestKapt(t *testing.T) {
- ctx, _ := testJava(t, `
+ bp := `
java_library {
name: "foo",
srcs: ["a.java", "b.kt"],
plugins: ["bar", "baz"],
+ errorprone: {
+ extra_check_modules: ["my_check"],
+ },
}
java_plugin {
@@ -102,64 +105,119 @@ func TestKapt(t *testing.T) {
processor_class: "com.baz",
srcs: ["b.java"],
}
- `)
- buildOS := android.BuildOs.String()
+ java_plugin {
+ name: "my_check",
+ srcs: ["b.java"],
+ }
+ `
+ t.Run("", func(t *testing.T) {
+ ctx, _ := testJava(t, bp)
- kapt := ctx.ModuleForTests("foo", "android_common").Rule("kapt")
- kotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
- javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
+ buildOS := android.BuildOs.String()
- bar := ctx.ModuleForTests("bar", buildOS+"_common").Rule("javac").Output.String()
- baz := ctx.ModuleForTests("baz", buildOS+"_common").Rule("javac").Output.String()
+ kapt := ctx.ModuleForTests("foo", "android_common").Rule("kapt")
+ kotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
+ javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
- // Test that the kotlin and java sources are passed to kapt and kotlinc
- if len(kapt.Inputs) != 2 || kapt.Inputs[0].String() != "a.java" || kapt.Inputs[1].String() != "b.kt" {
- t.Errorf(`foo kapt inputs %v != ["a.java", "b.kt"]`, kapt.Inputs)
- }
- if len(kotlinc.Inputs) != 2 || kotlinc.Inputs[0].String() != "a.java" || kotlinc.Inputs[1].String() != "b.kt" {
- t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, kotlinc.Inputs)
- }
+ bar := ctx.ModuleForTests("bar", buildOS+"_common").Rule("javac").Output.String()
+ baz := ctx.ModuleForTests("baz", buildOS+"_common").Rule("javac").Output.String()
- // Test that only the java sources are passed to javac
- if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
- t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
- }
+ // Test that the kotlin and java sources are passed to kapt and kotlinc
+ if len(kapt.Inputs) != 2 || kapt.Inputs[0].String() != "a.java" || kapt.Inputs[1].String() != "b.kt" {
+ t.Errorf(`foo kapt inputs %v != ["a.java", "b.kt"]`, kapt.Inputs)
+ }
+ if len(kotlinc.Inputs) != 2 || kotlinc.Inputs[0].String() != "a.java" || kotlinc.Inputs[1].String() != "b.kt" {
+ t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, kotlinc.Inputs)
+ }
- // Test that the kapt srcjar is a dependency of kotlinc and javac rules
- if !inList(kapt.Output.String(), kotlinc.Implicits.Strings()) {
- t.Errorf("expected %q in kotlinc implicits %v", kapt.Output.String(), kotlinc.Implicits.Strings())
- }
- if !inList(kapt.Output.String(), javac.Implicits.Strings()) {
- t.Errorf("expected %q in javac implicits %v", kapt.Output.String(), javac.Implicits.Strings())
- }
+ // Test that only the java sources are passed to javac
+ if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
+ t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
+ }
- // Test that the kapt srcjar is extracted by the kotlinc and javac rules
- if kotlinc.Args["srcJars"] != kapt.Output.String() {
- t.Errorf("expected %q in kotlinc srcjars %v", kapt.Output.String(), kotlinc.Args["srcJars"])
- }
- if javac.Args["srcJars"] != kapt.Output.String() {
- t.Errorf("expected %q in javac srcjars %v", kapt.Output.String(), kotlinc.Args["srcJars"])
- }
+ // Test that the kapt srcjar is a dependency of kotlinc and javac rules
+ if !inList(kapt.Output.String(), kotlinc.Implicits.Strings()) {
+ t.Errorf("expected %q in kotlinc implicits %v", kapt.Output.String(), kotlinc.Implicits.Strings())
+ }
+ if !inList(kapt.Output.String(), javac.Implicits.Strings()) {
+ t.Errorf("expected %q in javac implicits %v", kapt.Output.String(), javac.Implicits.Strings())
+ }
- // Test that the processors are passed to kapt
- expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar +
- " -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz
- if kapt.Args["kaptProcessorPath"] != expectedProcessorPath {
- t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kapt.Args["kaptProcessorPath"])
- }
- expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz"
- if kapt.Args["kaptProcessor"] != expectedProcessor {
- t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kapt.Args["kaptProcessor"])
- }
+ // Test that the kapt srcjar is extracted by the kotlinc and javac rules
+ if kotlinc.Args["srcJars"] != kapt.Output.String() {
+ t.Errorf("expected %q in kotlinc srcjars %v", kapt.Output.String(), kotlinc.Args["srcJars"])
+ }
+ if javac.Args["srcJars"] != kapt.Output.String() {
+ t.Errorf("expected %q in javac srcjars %v", kapt.Output.String(), kotlinc.Args["srcJars"])
+ }
- // Test that the processors are not passed to javac
- if javac.Args["processorPath"] != "" {
- t.Errorf("expected processorPath '', got %q", javac.Args["processorPath"])
- }
- if javac.Args["processor"] != "-proc:none" {
- t.Errorf("expected processor '-proc:none', got %q", javac.Args["processor"])
- }
+ // Test that the processors are passed to kapt
+ expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar +
+ " -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz
+ if kapt.Args["kaptProcessorPath"] != expectedProcessorPath {
+ t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kapt.Args["kaptProcessorPath"])
+ }
+ expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz"
+ if kapt.Args["kaptProcessor"] != expectedProcessor {
+ t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kapt.Args["kaptProcessor"])
+ }
+
+ // Test that the processors are not passed to javac
+ if javac.Args["processorpath"] != "" {
+ t.Errorf("expected processorPath '', got %q", javac.Args["processorpath"])
+ }
+ if javac.Args["processor"] != "-proc:none" {
+ t.Errorf("expected processor '-proc:none', got %q", javac.Args["processor"])
+ }
+ })
+
+ t.Run("errorprone", func(t *testing.T) {
+ env := map[string]string{
+ "RUN_ERROR_PRONE": "true",
+ }
+ config := testConfig(env, bp, nil)
+ ctx, _ := testJavaWithConfig(t, config)
+
+ buildOS := android.BuildOs.String()
+
+ kapt := ctx.ModuleForTests("foo", "android_common").Rule("kapt")
+ //kotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
+ javac := ctx.ModuleForTests("foo", "android_common").Description("javac")
+ errorprone := ctx.ModuleForTests("foo", "android_common").Description("errorprone")
+
+ bar := ctx.ModuleForTests("bar", buildOS+"_common").Description("javac").Output.String()
+ baz := ctx.ModuleForTests("baz", buildOS+"_common").Description("javac").Output.String()
+ myCheck := ctx.ModuleForTests("my_check", buildOS+"_common").Description("javac").Output.String()
+
+ // Test that the errorprone plugins are not passed to kapt
+ expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar +
+ " -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz
+ if kapt.Args["kaptProcessorPath"] != expectedProcessorPath {
+ t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kapt.Args["kaptProcessorPath"])
+ }
+ expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz"
+ if kapt.Args["kaptProcessor"] != expectedProcessor {
+ t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kapt.Args["kaptProcessor"])
+ }
+
+ // Test that the errorprone plugins are not passed to javac
+ if javac.Args["processorpath"] != "" {
+ t.Errorf("expected processorPath '', got %q", javac.Args["processorpath"])
+ }
+ if javac.Args["processor"] != "-proc:none" {
+ t.Errorf("expected processor '-proc:none', got %q", javac.Args["processor"])
+ }
+
+ // Test that the errorprone plugins are passed to errorprone
+ expectedProcessorPath = "-processorpath " + myCheck
+ if errorprone.Args["processorpath"] != expectedProcessorPath {
+ t.Errorf("expected processorpath %q, got %q", expectedProcessorPath, errorprone.Args["processorpath"])
+ }
+ if errorprone.Args["processor"] != "-proc:none" {
+ t.Errorf("expected processor '-proc:none', got %q", errorprone.Args["processor"])
+ }
+ })
}
func TestKaptEncodeFlags(t *testing.T) {
diff --git a/java/lint.go b/java/lint.go
index 3df582f6e..cd2a904d6 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -176,9 +176,9 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext,
// 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.
resourcesList = android.PathForModuleOut(ctx, "lint", "resources.list")
- resListRule := android.NewRuleBuilder()
+ resListRule := android.NewRuleBuilder(pctx, ctx)
resListRule.Command().Text("cp").FlagWithRspFileInputList("", l.resources).Output(resourcesList)
- resListRule.Build(pctx, ctx, "lint_resources_list", "lint resources list")
+ resListRule.Build("lint_resources_list", "lint resources list")
deps = append(deps, l.resources...)
}
@@ -192,7 +192,7 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext,
srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
cmd := rule.Command().
- BuiltTool(ctx, "lint-project-xml").
+ BuiltTool("lint-project-xml").
FlagWithOutput("--project_out ", projectXMLPath).
FlagWithOutput("--config_out ", configXMLPath).
FlagWithArg("--name ", ctx.ModuleName())
@@ -284,7 +284,7 @@ func (l *linter) lint(ctx android.ModuleContext) {
}
}
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
if l.manifest == nil {
manifest := l.generateManifest(ctx, rule)
@@ -347,7 +347,7 @@ func (l *linter) lint(ctx android.ModuleContext) {
rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String())
- rule.Build(pctx, ctx, "lint", "lint")
+ rule.Build("lint", "lint")
l.outputs = lintOutputs{
html: html,
@@ -447,7 +447,7 @@ func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
var outputs []*lintOutputs
var dirs []string
ctx.VisitAllModules(func(m android.Module) {
- if ctx.Config().EmbeddedInMake() && !m.ExportedToMake() {
+ if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
return
}
@@ -511,12 +511,12 @@ func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android
return paths[i].String() < paths[j].String()
})
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
- rule.Command().BuiltTool(ctx, "soong_zip").
+ rule.Command().BuiltTool("soong_zip").
FlagWithOutput("-o ", outputPath).
FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
FlagWithRspFileInputList("-r ", paths)
- rule.Build(pctx, ctx, outputPath.Base(), outputPath.Base())
+ rule.Build(outputPath.Base(), outputPath.Base())
}
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index cb8e6841a..9bc821dfe 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -86,15 +86,15 @@ func (p *platformCompatConfigSingleton) GenerateBuildActions(ctx android.Singlet
return
}
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
outputPath := platformCompatConfigPath(ctx)
rule.Command().
- BuiltTool(ctx, "process-compat-config").
+ BuiltTool("process-compat-config").
FlagForEachInput("--xml ", compatConfigMetadata).
FlagWithOutput("--merged-config ", outputPath)
- rule.Build(pctx, ctx, "merged-compat-config", "Merge compat config")
+ rule.Build("merged-compat-config", "Merge compat config")
p.metadata = outputPath
}
@@ -106,7 +106,7 @@ func (p *platformCompatConfigSingleton) MakeVars(ctx android.MakeVarsContext) {
}
func (p *platformCompatConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
configFileName := p.Name() + ".xml"
metadataFileName := p.Name() + "_meta.xml"
@@ -115,13 +115,13 @@ func (p *platformCompatConfig) GenerateAndroidBuildActions(ctx android.ModuleCon
path := android.PathForModuleSrc(ctx, String(p.properties.Src))
rule.Command().
- BuiltTool(ctx, "process-compat-config").
+ BuiltTool("process-compat-config").
FlagWithInput("--jar ", path).
FlagWithOutput("--device-config ", p.configFile).
FlagWithOutput("--merged-config ", p.metadataFile)
p.installDirPath = android.PathForModuleInstall(ctx, "etc", "compatconfig")
- rule.Build(pctx, ctx, configFileName, "Extract compat/compat_config.xml and install it")
+ rule.Build(configFileName, "Extract compat/compat_config.xml and install it")
}
diff --git a/java/proto.go b/java/proto.go
index 4d735ebbe..cc9abbeee 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -34,7 +34,7 @@ func genProto(ctx android.ModuleContext, protoFiles android.Paths, flags android
outDir := srcJarFile.ReplaceExtension(ctx, "tmp")
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().Text("rm -rf").Flag(outDir.String())
rule.Command().Text("mkdir -p").Flag(outDir.String())
@@ -42,13 +42,13 @@ func genProto(ctx android.ModuleContext, protoFiles android.Paths, flags android
for _, protoFile := range shard {
depFile := srcJarFile.InSameDir(ctx, protoFile.String()+".d")
rule.Command().Text("mkdir -p").Flag(filepath.Dir(depFile.String()))
- android.ProtoRule(ctx, rule, protoFile, flags, flags.Deps, outDir, depFile, nil)
+ android.ProtoRule(rule, protoFile, flags, flags.Deps, outDir, depFile, nil)
}
// Proto generated java files have an unknown package name in the path, so package the entire output directory
// into a srcjar.
rule.Command().
- BuiltTool(ctx, "soong_zip").
+ BuiltTool("soong_zip").
Flag("-jar").
Flag("-write_if_changed").
FlagWithOutput("-o ", srcJarFile).
@@ -66,7 +66,7 @@ func genProto(ctx android.ModuleContext, protoFiles android.Paths, flags android
ruleDesc += " " + strconv.Itoa(i)
}
- rule.Build(pctx, ctx, ruleName, ruleDesc)
+ rule.Build(ruleName, ruleDesc)
}
return srcJarFiles
diff --git a/java/robolectric.go b/java/robolectric.go
index 04fc11722..419efda88 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -199,7 +199,7 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext)
func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath,
instrumentedApp *AndroidApp) {
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
manifest := instrumentedApp.mergedManifestFile
resourceApk := instrumentedApp.outputFile
@@ -213,11 +213,11 @@ func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.Writab
Implicit(manifest).
Implicit(resourceApk)
- rule.Build(pctx, ctx, "generate_test_config", "generate test_config.properties")
+ rule.Build("generate_test_config", "generate test_config.properties")
}
func generateSameDirRoboTestConfigJar(ctx android.ModuleContext, outputFile android.ModuleOutPath) {
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
outputDir := outputFile.InSameDir(ctx)
configFile := outputDir.Join(ctx, "com/android/tools/test_config.properties")
@@ -230,12 +230,12 @@ func generateSameDirRoboTestConfigJar(ctx android.ModuleContext, outputFile andr
Textf(`echo "android_resource_apk=%s.apk"`, ctx.ModuleName()).
Text(") >>").Output(configFile)
rule.Command().
- BuiltTool(ctx, "soong_zip").
+ BuiltTool("soong_zip").
FlagWithArg("-C ", outputDir.String()).
FlagWithInput("-f ", configFile).
FlagWithOutput("-o ", outputFile)
- rule.Build(pctx, ctx, "generate_test_config_samedir", "generate test_config.properties")
+ rule.Build("generate_test_config_samedir", "generate test_config.properties")
}
func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFile android.WritablePath,
@@ -389,8 +389,10 @@ func (r *robolectricRuntimes) GenerateAndroidBuildActions(ctx android.ModuleCont
}
runtimeFromSourceJar := android.OutputFileForModule(ctx, runtimeFromSourceModule, "")
+ // TODO(murj) Update this to ctx.Config().PlatformSdkCodename() once the platform
+ // classes like android.os.Build are updated to S.
runtimeName := fmt.Sprintf("android-all-%s-robolectric-r0.jar",
- ctx.Config().PlatformSdkCodename())
+ "R")
installedRuntime := ctx.InstallFile(androidAllDir, runtimeName, runtimeFromSourceJar)
r.runtimes = append(r.runtimes, installedRuntime)
}
diff --git a/java/sdk.go b/java/sdk.go
index 971791f4a..32a4b5a88 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -544,7 +544,7 @@ func createSdkFrameworkAidl(ctx android.SingletonContext) {
commitChangeForRestat(rule, tempPath, combinedAidl)
- rule.Build(pctx, ctx, "framework_aidl", "generate framework.aidl")
+ rule.Build("framework_aidl", "generate framework.aidl")
}
// Creates a version of framework.aidl for the non-updatable part of the platform.
@@ -558,7 +558,7 @@ func createNonUpdatableFrameworkAidl(ctx android.SingletonContext) {
commitChangeForRestat(rule, tempPath, combinedAidl)
- rule.Build(pctx, ctx, "framework_non_updatable_aidl", "generate framework_non_updatable.aidl")
+ rule.Build("framework_non_updatable_aidl", "generate framework_non_updatable.aidl")
}
func createFrameworkAidl(stubsModules []string, path android.OutputPath, ctx android.SingletonContext) *android.RuleBuilder {
@@ -586,7 +586,7 @@ func createFrameworkAidl(stubsModules []string, path android.OutputPath, ctx and
}
}
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.MissingDeps(missingDeps)
var aidls android.Paths
@@ -597,7 +597,7 @@ func createFrameworkAidl(stubsModules []string, path android.OutputPath, ctx and
rule.Command().
Text("rm -f").Output(aidl)
rule.Command().
- BuiltTool(ctx, "sdkparcelables").
+ BuiltTool("sdkparcelables").
Input(jar).
Output(aidl)
@@ -632,7 +632,7 @@ func nonUpdatableFrameworkAidlPath(ctx android.PathContext) android.OutputPath {
func createAPIFingerprint(ctx android.SingletonContext) {
out := ApiFingerprintPath(ctx)
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
Text("rm -f").Output(out)
@@ -659,7 +659,7 @@ func createAPIFingerprint(ctx android.SingletonContext) {
Output(out)
}
- rule.Build(pctx, ctx, "api_fingerprint", "generate api_fingerprint.txt")
+ rule.Build("api_fingerprint", "generate api_fingerprint.txt")
}
func ApiFingerprintPath(ctx android.PathContext) android.OutputPath {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 21c03cd39..4e33d747b 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -435,8 +435,23 @@ type sdkLibraryProperties struct {
// If set to true, the path of dist files is apistubs/core. Defaults to false.
Core_lib *bool
- // don't create dist rules.
- No_dist *bool `blueprint:"mutated"`
+ // If set to true then don't create dist rules.
+ No_dist *bool
+
+ // The stem for the artifacts that are copied to the dist, if not specified
+ // then defaults to the base module name.
+ //
+ // For each scope the following artifacts are copied to the apistubs/<scope>
+ // directory in the dist.
+ // * stubs impl jar -> <dist-stem>.jar
+ // * API specification file -> api/<dist-stem>.txt
+ // * Removed API specification file -> api/<dist-stem>-removed.txt
+ //
+ // Also used to construct the name of the filegroup (created by prebuilt_apis)
+ // that references the latest released API and remove API specification files.
+ // * API specification filegroup -> <dist-stem>.api.<scope>.latest
+ // * Removed API specification filegroup -> <dist-stem>-removed.api.<scope>.latest
+ Dist_stem *string
// indicates whether system and test apis should be generated.
Generate_system_and_test_apis bool `blueprint:"mutated"`
@@ -1109,12 +1124,16 @@ func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.EarlyModuleCont
}
}
+func (module *SdkLibrary) distStem() string {
+ return proptools.StringDefault(module.sdkLibraryProperties.Dist_stem, module.BaseModuleName())
+}
+
func (module *SdkLibrary) latestApiFilegroupName(apiScope *apiScope) string {
- return ":" + module.BaseModuleName() + ".api." + apiScope.name + ".latest"
+ return ":" + module.distStem() + ".api." + apiScope.name + ".latest"
}
func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope *apiScope) string {
- return ":" + module.BaseModuleName() + "-removed.api." + apiScope.name + ".latest"
+ return ":" + module.distStem() + "-removed.api." + apiScope.name + ".latest"
}
func childModuleVisibility(childVisibility []string) []string {
@@ -1220,7 +1239,7 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext
// Dist the class jar 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.jar", module.BaseModuleName()))
+ props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.distStem()))
props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
props.Dist.Tag = proptools.StringPtr(".jar")
}
@@ -1262,11 +1281,7 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC
Include_dirs []string
Local_include_dirs []string
}
- Dist struct {
- Targets []string
- Dest *string
- Dir *string
- }
+ Dists []android.Dist
}{}
// The stubs source processing uses the same compile time classpath when extracting the
@@ -1366,11 +1381,23 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC
}
}
- // 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 and removed api txt artifacts for sdk builds.
+ distDir := proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
+ for _, p := range []struct {
+ tag string
+ pattern string
+ }{
+ {tag: ".api.txt", pattern: "%s.txt"},
+ {tag: ".removed-api.txt", pattern: "%s-removed.txt"},
+ } {
+ props.Dists = append(props.Dists, android.Dist{
+ Targets: []string{"sdk", "win_sdk"},
+ Dir: distDir,
+ Dest: proptools.StringPtr(fmt.Sprintf(p.pattern, module.distStem())),
+ Tag: proptools.StringPtr(p.tag),
+ })
+ }
}
mctx.CreateModule(DroidstubsFactory, &props)
@@ -1474,10 +1501,6 @@ func (module *SdkLibrary) SdkImplementationJars(ctx android.BaseModuleContext, s
return module.sdkJars(ctx, sdkVersion, false /*headerJars*/)
}
-func (module *SdkLibrary) SetNoDist() {
- module.sdkLibraryProperties.No_dist = proptools.BoolPtr(true)
-}
-
var javaSdkLibrariesKey = android.NewOnceKey("javaSdkLibraries")
func javaSdkLibraries(config android.Config) *[]string {
@@ -1505,12 +1528,10 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont
}
// If this builds against standard libraries (i.e. is not part of the core libraries)
- // then assume it provides both system and test apis. Otherwise, assume it does not and
- // also assume it does not contribute to the dist build.
+ // then assume it provides both system and test apis.
sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
hasSystemAndTestApis := sdkDep.hasStandardLibs()
module.sdkLibraryProperties.Generate_system_and_test_apis = hasSystemAndTestApis
- module.sdkLibraryProperties.No_dist = proptools.BoolPtr(!hasSystemAndTestApis)
missing_current_api := false
@@ -2155,12 +2176,12 @@ func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleConte
xmlContent := fmt.Sprintf(permissionsTemplate, libName, module.implPath(ctx))
module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath
- rule := android.NewRuleBuilder()
+ rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
Text("/bin/bash -c \"echo -e '" + xmlContent + "'\" > ").
Output(module.outputFilePath)
- rule.Build(pctx, ctx, "java_sdk_xml", "Permission XML")
+ rule.Build("java_sdk_xml", "Permission XML")
module.installDirPath = android.PathForModuleInstall(ctx, "etc", module.SubDir())
}
@@ -2292,11 +2313,10 @@ func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberCo
scopeSet.AddProperty("jars", jars)
// Merge the stubs source jar into the snapshot zip so that when it is unpacked
- // the source files are also unpacked. Use a glob so that if the directory is missing
- // (because there are no stubs sources for this scope) it will not fail.
+ // the source files are also unpacked.
snapshotRelativeDir := filepath.Join(scopeDir, ctx.Name()+"_stub_sources")
ctx.SnapshotBuilder().UnzipToSnapshot(properties.StubsSrcJar, snapshotRelativeDir)
- scopeSet.AddProperty("stub_srcs", []string{snapshotRelativeDir + "/**/*.java"})
+ scopeSet.AddProperty("stub_srcs", []string{snapshotRelativeDir})
if properties.CurrentApiFile != nil {
currentApiSnapshotPath := filepath.Join(scopeDir, ctx.Name()+".txt")
diff --git a/java/sdk_library_external.go b/java/sdk_library_external.go
new file mode 100644
index 000000000..293493685
--- /dev/null
+++ b/java/sdk_library_external.go
@@ -0,0 +1,109 @@
+// 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"
+)
+
+type partitionGroup int
+
+// Representation of partition group for checking inter-partition library dependencies.
+// Between system and system_ext, there are no restrictions of dependencies,
+// so we can treat these partitions as the same in terms of inter-partition dependency.
+// Same policy is applied between vendor and odm partiton.
+const (
+ partitionGroupNone partitionGroup = iota
+ // group for system, and system_ext partition
+ partitionGroupSystem
+ // group for vendor and odm partition
+ partitionGroupVendor
+ // product partition
+ partitionGroupProduct
+)
+
+func (g partitionGroup) String() string {
+ switch g {
+ case partitionGroupSystem:
+ return "system"
+ case partitionGroupVendor:
+ return "vendor"
+ case partitionGroupProduct:
+ return "product"
+ }
+
+ return ""
+}
+
+// Get partition group of java module that can be used at inter-partition dependency check.
+// We currently have three groups
+// (system, system_ext) => system partition group
+// (vendor, odm) => vendor partition group
+// (product) => product partition group
+func (j *Module) partitionGroup(ctx android.EarlyModuleContext) partitionGroup {
+ // system and system_ext partition can be treated as the same in terms of inter-partition dependency.
+ if j.Platform() || j.SystemExtSpecific() {
+ return partitionGroupSystem
+ }
+
+ // vendor and odm partition can be treated as the same in terms of inter-partition dependency.
+ if j.SocSpecific() || j.DeviceSpecific() {
+ return partitionGroupVendor
+ }
+
+ // product partition is independent.
+ if j.ProductSpecific() {
+ return partitionGroupProduct
+ }
+
+ panic("Cannot determine partition type")
+}
+
+func (j *Module) allowListedInterPartitionJavaLibrary(ctx android.EarlyModuleContext) bool {
+ return inList(j.Name(), ctx.Config().InterPartitionJavaLibraryAllowList())
+}
+
+type javaSdkLibraryEnforceContext interface {
+ Name() string
+ allowListedInterPartitionJavaLibrary(ctx android.EarlyModuleContext) bool
+ partitionGroup(ctx android.EarlyModuleContext) partitionGroup
+}
+
+var _ javaSdkLibraryEnforceContext = (*Module)(nil)
+
+func (j *Module) checkPartitionsForJavaDependency(ctx android.EarlyModuleContext, propName string, dep javaSdkLibraryEnforceContext) {
+ if dep.allowListedInterPartitionJavaLibrary(ctx) {
+ return
+ }
+
+ // If product interface is not enforced, skip check between system and product partition.
+ // But still need to check between product and vendor partition because product interface flag
+ // just represents enforcement between product and system, and vendor interface enforcement
+ // that is enforced here by precondition is representing enforcement between vendor and other partitions.
+ if !ctx.Config().EnforceProductPartitionInterface() {
+ productToSystem := j.partitionGroup(ctx) == partitionGroupProduct && dep.partitionGroup(ctx) == partitionGroupSystem
+ systemToProduct := j.partitionGroup(ctx) == partitionGroupSystem && dep.partitionGroup(ctx) == partitionGroupProduct
+
+ if productToSystem || systemToProduct {
+ return
+ }
+ }
+
+ // If module and dependency library is inter-partition
+ if j.partitionGroup(ctx) != dep.partitionGroup(ctx) {
+ errorFormat := "dependency on java_library (%q) is not allowed across the partitions (%s -> %s), use java_sdk_library instead"
+ ctx.PropertyErrorf(propName, errorFormat, dep.Name(), j.partitionGroup(ctx), dep.partitionGroup(ctx))
+ }
+}
diff --git a/java/sysprop.go b/java/sysprop.go
index 1a70499b8..e41aef68a 100644
--- a/java/sysprop.go
+++ b/java/sysprop.go
@@ -14,6 +14,10 @@
package java
+// This file contains a map to redirect dependencies towards sysprop_library. If a sysprop_library
+// is owned by Platform, and the client module links against system API, the public stub of the
+// sysprop_library should be used. The map will contain public stub names of sysprop_libraries.
+
import (
"sync"