summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--android/apex.go18
-rw-r--r--android/api_levels.go4
-rw-r--r--apex/Android.bp1
-rw-r--r--apex/apex.go14
-rw-r--r--apex/apex_test.go280
-rw-r--r--apex/boot_image_test.go128
-rw-r--r--apex/builder.go4
-rw-r--r--cc/androidmk.go6
-rw-r--r--java/Android.bp2
-rw-r--r--java/boot_image.go85
-rw-r--r--java/boot_image_test.go31
-rw-r--r--java/boot_jars.go34
-rw-r--r--java/dexpreopt_bootjars.go28
-rw-r--r--java/prebuilt_apis.go101
-rw-r--r--java/testing.go11
-rw-r--r--rust/androidmk.go7
-rw-r--r--rust/rust_test.go1
-rw-r--r--rust/test.go17
-rw-r--r--rust/test_test.go7
19 files changed, 726 insertions, 53 deletions
diff --git a/android/apex.go b/android/apex.go
index 31c62e994..b87ff09e2 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -111,6 +111,19 @@ func (i ApexInfo) InApex(apex string) bool {
return false
}
+// InApexByBaseName tells whether this apex variant of the module is part of the given APEX or not,
+// where the APEX is specified by its canonical base name, i.e. typically beginning with
+// "com.android.". In particular this function doesn't differentiate between source and prebuilt
+// APEXes, where the latter may have "prebuilt_" prefixes.
+func (i ApexInfo) InApexByBaseName(apex string) bool {
+ for _, a := range i.InApexes {
+ if RemoveOptionalPrebuiltPrefix(a) == apex {
+ return true
+ }
+ }
+ return false
+}
+
// ApexTestForInfo stores the contents of APEXes for which this module is a test - although this
// module is not part of the APEX - and thus has access to APEX internals.
type ApexTestForInfo struct {
@@ -830,9 +843,8 @@ func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion ApiL
return
}
- // do not enforce deps.min_sdk_version if APEX/APK doesn't set min_sdk_version or
- // min_sdk_version is not finalized (e.g. current or codenames)
- if minSdkVersion.IsCurrent() {
+ // do not enforce deps.min_sdk_version if APEX/APK doesn't set min_sdk_version
+ if minSdkVersion.IsNone() {
return
}
diff --git a/android/api_levels.go b/android/api_levels.go
index 08328e16d..1b53f3f2a 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -81,6 +81,10 @@ func (this ApiLevel) IsCurrent() bool {
return this.value == "current"
}
+func (this ApiLevel) IsNone() bool {
+ return this.number == -1
+}
+
// Returns -1 if the current API level is less than the argument, 0 if they
// are equal, and 1 if it is greater than the argument.
func (this ApiLevel) CompareTo(other ApiLevel) int {
diff --git a/apex/Android.bp b/apex/Android.bp
index 77dde72ac..b6fdcf415 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -25,6 +25,7 @@ bootstrap_go_package {
],
testSrcs: [
"apex_test.go",
+ "boot_image_test.go",
"vndk_test.go",
],
pluginFor: ["soong_build"],
diff --git a/apex/apex.go b/apex/apex.go
index 384d6c7a6..ade8fa909 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -854,11 +854,17 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) {
Contents: apexContents,
})
+ minSdkVersion := a.minSdkVersion(mctx)
+ // When min_sdk_version is not set, the apex is built against FutureApiLevel.
+ if minSdkVersion.IsNone() {
+ minSdkVersion = android.FutureApiLevel
+ }
+
// This is the main part of this mutator. Mark the collected dependencies that they need to
// be built for this apexBundle.
apexInfo := android.ApexInfo{
ApexVariationName: mctx.ModuleName(),
- MinSdkVersionStr: a.minSdkVersion(mctx).String(),
+ MinSdkVersionStr: minSdkVersion.String(),
RequiredSdks: a.RequiredSdks(),
Updatable: a.Updatable(),
InApexes: []string{mctx.ModuleName()},
@@ -2116,17 +2122,13 @@ func (a *apexBundle) checkMinSdkVersion(ctx android.ModuleContext) {
func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) android.ApiLevel {
ver := proptools.String(a.properties.Min_sdk_version)
if ver == "" {
- return android.FutureApiLevel
+ return android.NoneApiLevel
}
apiLevel, err := android.ApiLevelFromUser(ctx, ver)
if err != nil {
ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
return android.NoneApiLevel
}
- if apiLevel.IsPreview() {
- // All codenames should build against "current".
- return android.FutureApiLevel
- }
return apiLevel
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index ae0cbe969..7f5be7ec5 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -2135,6 +2135,74 @@ func TestApexMinSdkVersion_OkayEvenWhenDepIsNewer_IfItSatisfiesApexMinSdkVersion
expectLink("mylib", "shared_apex30", "mylib2", "shared_apex30")
}
+func TestApexMinSdkVersion_WorksWithSdkCodename(t *testing.T) {
+ withSAsActiveCodeNames := func(fs map[string][]byte, config android.Config) {
+ config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("S")
+ config.TestProductVariables.Platform_version_active_codenames = []string{"S"}
+ }
+ testApexError(t, `libbar.*: should support min_sdk_version\(S\)`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo"],
+ min_sdk_version: "S",
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ cc_library {
+ name: "libfoo",
+ shared_libs: ["libbar"],
+ apex_available: ["myapex"],
+ min_sdk_version: "29",
+ }
+ cc_library {
+ name: "libbar",
+ apex_available: ["myapex"],
+ }
+ `, withSAsActiveCodeNames)
+}
+
+func TestApexMinSdkVersion_WorksWithActiveCodenames(t *testing.T) {
+ withSAsActiveCodeNames := func(fs map[string][]byte, config android.Config) {
+ config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("S")
+ config.TestProductVariables.Platform_version_active_codenames = []string{"S", "T"}
+ }
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo"],
+ min_sdk_version: "S",
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ cc_library {
+ name: "libfoo",
+ shared_libs: ["libbar"],
+ apex_available: ["myapex"],
+ min_sdk_version: "S",
+ }
+ cc_library {
+ name: "libbar",
+ stubs: {
+ symbol_file: "libbar.map.txt",
+ versions: ["30", "S", "T"],
+ },
+ }
+ `, withSAsActiveCodeNames)
+
+ // ensure libfoo is linked with "S" version of libbar stub
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared_apex10000")
+ libFlags := libfoo.Rule("ld").Args["libFlags"]
+ ensureContains(t, libFlags, "android_arm64_armv8-a_shared_S/libbar.so")
+}
+
func TestFilesInSubDir(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -4330,6 +4398,215 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) {
})
}
+func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
+ transform := func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = android.CreateTestConfiguredJarList([]string{"myapex:libfoo"})
+ }
+
+ checkBootDexJarPath := func(ctx *android.TestContext, bootDexJarPath string) {
+ s := ctx.SingletonForTests("dex_bootjars")
+ foundLibfooJar := false
+ for _, output := range s.AllOutputs() {
+ if strings.HasSuffix(output, "/libfoo.jar") {
+ foundLibfooJar = true
+ buildRule := s.Output(output)
+ actual := android.NormalizePathForTesting(buildRule.Input)
+ if actual != bootDexJarPath {
+ t.Errorf("Incorrect boot dex jar path '%s', expected '%s'", actual, bootDexJarPath)
+ }
+ }
+ }
+ if !foundLibfooJar {
+ t.Errorf("Rule for libfoo.jar missing in dex_bootjars singleton outputs")
+ }
+ }
+
+ t.Run("prebuilt only", func(t *testing.T) {
+ bp := `
+ prebuilt_apex {
+ name: "myapex",
+ arch: {
+ arm64: {
+ src: "myapex-arm64.apex",
+ },
+ arm: {
+ src: "myapex-arm.apex",
+ },
+ },
+ exported_java_libs: ["libfoo"],
+ }
+
+ java_import {
+ name: "libfoo",
+ jars: ["libfoo.jar"],
+ apex_available: ["myapex"],
+ }
+ `
+
+ ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ checkBootDexJarPath(ctx, ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
+ })
+
+ t.Run("prebuilt with source library preferred", func(t *testing.T) {
+ bp := `
+ prebuilt_apex {
+ name: "myapex",
+ arch: {
+ arm64: {
+ src: "myapex-arm64.apex",
+ },
+ arm: {
+ src: "myapex-arm.apex",
+ },
+ },
+ exported_java_libs: ["libfoo"],
+ }
+
+ java_import {
+ name: "libfoo",
+ jars: ["libfoo.jar"],
+ apex_available: ["myapex"],
+ }
+
+ java_library {
+ name: "libfoo",
+ srcs: ["foo/bar/MyClass.java"],
+ apex_available: ["myapex"],
+ }
+ `
+
+ // In this test the source (java_library) libfoo is active since the
+ // prebuilt (java_import) defaults to prefer:false. However the
+ // prebuilt_apex module always depends on the prebuilt, and so it doesn't
+ // find the dex boot jar in it. We either need to disable the source libfoo
+ // or make the prebuilt libfoo preferred.
+ testDexpreoptWithApexes(t, bp, "failed to find a dex jar path for module 'libfoo'", transform)
+ })
+
+ t.Run("prebuilt library preferred with source", func(t *testing.T) {
+ bp := `
+ prebuilt_apex {
+ name: "myapex",
+ arch: {
+ arm64: {
+ src: "myapex-arm64.apex",
+ },
+ arm: {
+ src: "myapex-arm.apex",
+ },
+ },
+ exported_java_libs: ["libfoo"],
+ }
+
+ java_import {
+ name: "libfoo",
+ prefer: true,
+ jars: ["libfoo.jar"],
+ apex_available: ["myapex"],
+ }
+
+ java_library {
+ name: "libfoo",
+ srcs: ["foo/bar/MyClass.java"],
+ apex_available: ["myapex"],
+ }
+ `
+
+ ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ checkBootDexJarPath(ctx, ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
+ })
+
+ t.Run("prebuilt with source apex preferred", func(t *testing.T) {
+ bp := `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ java_libs: ["libfoo"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ prebuilt_apex {
+ name: "myapex",
+ arch: {
+ arm64: {
+ src: "myapex-arm64.apex",
+ },
+ arm: {
+ src: "myapex-arm.apex",
+ },
+ },
+ exported_java_libs: ["libfoo"],
+ }
+
+ java_import {
+ name: "libfoo",
+ jars: ["libfoo.jar"],
+ apex_available: ["myapex"],
+ }
+
+ java_library {
+ name: "libfoo",
+ srcs: ["foo/bar/MyClass.java"],
+ apex_available: ["myapex"],
+ }
+ `
+
+ ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ checkBootDexJarPath(ctx, ".intermediates/libfoo/android_common_apex10000/aligned/libfoo.jar")
+ })
+
+ t.Run("prebuilt preferred with source apex disabled", func(t *testing.T) {
+ bp := `
+ apex {
+ name: "myapex",
+ enabled: false,
+ key: "myapex.key",
+ java_libs: ["libfoo"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ prebuilt_apex {
+ name: "myapex",
+ arch: {
+ arm64: {
+ src: "myapex-arm64.apex",
+ },
+ arm: {
+ src: "myapex-arm.apex",
+ },
+ },
+ exported_java_libs: ["libfoo"],
+ }
+
+ java_import {
+ name: "libfoo",
+ prefer: true,
+ jars: ["libfoo.jar"],
+ apex_available: ["myapex"],
+ }
+
+ java_library {
+ name: "libfoo",
+ srcs: ["foo/bar/MyClass.java"],
+ apex_available: ["myapex"],
+ }
+ `
+
+ ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ checkBootDexJarPath(ctx, ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
+ })
+}
+
func TestApexWithTests(t *testing.T) {
ctx, config := testApex(t, `
apex_test {
@@ -5934,10 +6211,11 @@ func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, transformDexpreopt
"build/make/target/product/security": nil,
"apex_manifest.json": nil,
"AndroidManifest.xml": nil,
+ "system/sepolicy/apex/myapex-file_contexts": nil,
"system/sepolicy/apex/some-updatable-apex-file_contexts": nil,
"system/sepolicy/apex/some-non-updatable-apex-file_contexts": nil,
"system/sepolicy/apex/com.android.art.debug-file_contexts": nil,
- "framework/aidl/a.aidl": nil,
+ "framework/aidl/a.aidl": nil,
}
cc.GatherRequiredFilesForTest(fs)
diff --git a/apex/boot_image_test.go b/apex/boot_image_test.go
new file mode 100644
index 000000000..07feb0358
--- /dev/null
+++ b/apex/boot_image_test.go
@@ -0,0 +1,128 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package apex
+
+import (
+ "testing"
+
+ "android/soong/android"
+ "android/soong/dexpreopt"
+ "android/soong/java"
+)
+
+// Contains tests for boot_image logic from java/boot_image.go as the ART boot image requires
+// modules from the ART apex.
+
+func TestBootImages(t *testing.T) {
+ ctx, _ := testApex(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["b.java"],
+ unsafe_ignore_missing_latest_api: true,
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ installable: true,
+ }
+
+ apex {
+ name: "com.android.art",
+ key: "com.android.art.key",
+ java_libs: [
+ "baz",
+ "quuz",
+ ],
+ }
+
+ apex_key {
+ name: "com.android.art.key",
+ public_key: "com.android.art.avbpubkey",
+ private_key: "com.android.art.pem",
+ }
+
+ java_library {
+ name: "baz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ }
+
+ java_library {
+ name: "quuz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ }
+`,
+ // Configure some libraries in the art and framework boot images.
+ withArtBootImageJars("com.android.art:baz", "com.android.art:quuz"),
+ withFrameworkBootImageJars("platform:foo", "platform:bar"),
+ withFiles(filesForSdkLibrary),
+ // Some additional files needed for the art apex.
+ withFiles(map[string][]byte{
+ "com.android.art.avbpubkey": nil,
+ "com.android.art.pem": nil,
+ "system/sepolicy/apex/com.android.art-file_contexts": nil,
+ }),
+ )
+
+ // Make sure that the framework-boot-image is using the correct configuration.
+ checkBootImage(t, ctx, "framework-boot-image", "platform:foo,platform:bar")
+
+ // Make sure that the art-boot-image is using the correct configuration.
+ checkBootImage(t, ctx, "art-boot-image", "com.android.art:baz,com.android.art:quuz")
+}
+
+func checkBootImage(t *testing.T, ctx *android.TestContext, moduleName string, expectedConfiguredModules string) {
+ t.Helper()
+
+ bootImage := ctx.ModuleForTests(moduleName, "android_common").Module().(*java.BootImageModule)
+
+ bootImageInfo := ctx.ModuleProvider(bootImage, java.BootImageInfoProvider).(java.BootImageInfo)
+ modules := bootImageInfo.Modules()
+ if actual := modules.String(); actual != expectedConfiguredModules {
+ t.Errorf("invalid modules for %s: expected %q, actual %q", moduleName, expectedConfiguredModules, actual)
+ }
+}
+
+func modifyDexpreoptConfig(configModifier func(dexpreoptConfig *dexpreopt.GlobalConfig)) func(fs map[string][]byte, config android.Config) {
+ return func(fs map[string][]byte, config android.Config) {
+ // Initialize the dexpreopt GlobalConfig to an empty structure. This has no effect if it has
+ // already been set.
+ pathCtx := android.PathContextForTesting(config)
+ dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
+ dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
+
+ // Retrieve the existing configuration and modify it.
+ dexpreoptConfig = dexpreopt.GetGlobalConfig(pathCtx)
+ configModifier(dexpreoptConfig)
+ }
+}
+
+func withArtBootImageJars(bootJars ...string) func(fs map[string][]byte, config android.Config) {
+ return modifyDexpreoptConfig(func(dexpreoptConfig *dexpreopt.GlobalConfig) {
+ dexpreoptConfig.ArtApexJars = android.CreateTestConfiguredJarList(bootJars)
+ })
+}
+
+func withFrameworkBootImageJars(bootJars ...string) func(fs map[string][]byte, config android.Config) {
+ return modifyDexpreoptConfig(func(dexpreoptConfig *dexpreopt.GlobalConfig) {
+ dexpreoptConfig.BootJars = android.CreateTestConfiguredJarList(bootJars)
+ })
+}
diff --git a/apex/builder.go b/apex/builder.go
index 67314d85b..16ca74cf2 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -598,7 +598,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
// bundletool doesn't understand what "current" is. We need to transform it to
// codename
- if moduleMinSdkVersion.IsCurrent() {
+ if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() {
minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
}
// apex module doesn't have a concept of target_sdk_version, hence for the time
@@ -780,7 +780,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
ctx.PropertyErrorf("test_only_force_compression", "not available")
return
}
- compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.properties.Compressible, true)
+ compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.properties.Compressible, false)
if apexType == imageApex && (compressionEnabled || a.testOnlyShouldForceCompression()) {
a.isCompressed = true
unsignedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+".capex.unsigned")
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 040aa0b9f..934572844 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -168,7 +168,7 @@ func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *and
}
}
-func androidMkWriteTestData(data []android.DataPath, ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+func AndroidMkWriteTestData(data []android.DataPath, entries *android.AndroidMkEntries) {
testFiles := android.AndroidMkDataPaths(data)
if len(testFiles) > 0 {
entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
@@ -353,7 +353,7 @@ func (benchmark *benchmarkDecorator) AndroidMkEntries(ctx AndroidMkContext, entr
for _, srcPath := range benchmark.data {
dataPaths = append(dataPaths, android.DataPath{SrcPath: srcPath})
}
- androidMkWriteTestData(dataPaths, ctx, entries)
+ AndroidMkWriteTestData(dataPaths, entries)
}
func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
@@ -378,7 +378,7 @@ func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.
}
})
- androidMkWriteTestData(test.data, ctx, entries)
+ AndroidMkWriteTestData(test.data, entries)
androidMkWriteExtraTestConfigs(test.extraTestConfigs, entries)
}
diff --git a/java/Android.bp b/java/Android.bp
index 9c28968f6..364566a8b 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -24,6 +24,7 @@ bootstrap_go_package {
"app.go",
"app_import.go",
"app_set.go",
+ "boot_image.go",
"boot_jars.go",
"builder.go",
"device_host_converter.go",
@@ -63,6 +64,7 @@ bootstrap_go_package {
"app_import_test.go",
"app_set_test.go",
"app_test.go",
+ "boot_image_test.go",
"device_host_converter_test.go",
"dexpreopt_test.go",
"dexpreopt_bootjars_test.go",
diff --git a/java/boot_image.go b/java/boot_image.go
new file mode 100644
index 000000000..07ef0d841
--- /dev/null
+++ b/java/boot_image.go
@@ -0,0 +1,85 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "strings"
+
+ "android/soong/android"
+ "github.com/google/blueprint"
+)
+
+func init() {
+ RegisterBootImageBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterBootImageBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("boot_image", bootImageFactory)
+}
+
+type bootImageProperties struct {
+ // The name of the image this represents.
+ //
+ // Must be one of "art" or "boot".
+ Image_name string
+}
+
+type BootImageModule struct {
+ android.ModuleBase
+
+ properties bootImageProperties
+}
+
+func bootImageFactory() android.Module {
+ m := &BootImageModule{}
+ m.AddProperties(&m.properties)
+ android.InitAndroidArchModule(m, android.HostAndDeviceDefault, android.MultilibCommon)
+ return m
+}
+
+var BootImageInfoProvider = blueprint.NewProvider(BootImageInfo{})
+
+type BootImageInfo struct {
+ // The image config, internal to this module (and the dex_bootjars singleton).
+ imageConfig *bootImageConfig
+}
+
+func (i BootImageInfo) Modules() android.ConfiguredJarList {
+ return i.imageConfig.modules
+}
+
+func (b *BootImageModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // Nothing to do if skipping the dexpreopt of boot image jars.
+ if SkipDexpreoptBootJars(ctx) {
+ return
+ }
+
+ // Get a map of the image configs that are supported.
+ imageConfigs := genBootImageConfigs(ctx)
+
+ // Retrieve the config for this image.
+ imageName := b.properties.Image_name
+ imageConfig := imageConfigs[imageName]
+ if imageConfig == nil {
+ ctx.PropertyErrorf("image_name", "Unknown image name %q, expected one of %s", imageName, strings.Join(android.SortedStringKeys(imageConfigs), ", "))
+ return
+ }
+
+ // Construct the boot image info from the config.
+ info := BootImageInfo{imageConfig: imageConfig}
+
+ // Make it available for other modules.
+ ctx.SetProvider(BootImageInfoProvider, info)
+}
diff --git a/java/boot_image_test.go b/java/boot_image_test.go
new file mode 100644
index 000000000..a29578292
--- /dev/null
+++ b/java/boot_image_test.go
@@ -0,0 +1,31 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "testing"
+)
+
+// Contains some simple tests for boot_image logic, additional tests can be found in
+// apex/boot_image_test.go as the ART boot image requires modules from the ART apex.
+
+func TestUnknownBootImage(t *testing.T) {
+ testJavaError(t, "image_name: Unknown image name \\\"unknown\\\", expected one of art, boot", `
+ boot_image {
+ name: "unknown-boot-image",
+ image_name: "unknown",
+ }
+`)
+}
diff --git a/java/boot_jars.go b/java/boot_jars.go
index 823275b1d..ac8107b7c 100644
--- a/java/boot_jars.go
+++ b/java/boot_jars.go
@@ -49,14 +49,36 @@ func populateMapFromConfiguredJarList(ctx android.SingletonContext, moduleToApex
return true
}
+// isActiveModule returns true if the given module should be considered for boot
+// jars, i.e. if it's enabled and the preferred one in case of source and
+// prebuilt alternatives.
+func isActiveModule(module android.Module) bool {
+ if !module.Enabled() {
+ return false
+ }
+ if module.IsReplacedByPrebuilt() {
+ // A source module that has been replaced by a prebuilt counterpart.
+ return false
+ }
+ if prebuilt, ok := module.(android.PrebuiltInterface); ok {
+ if p := prebuilt.Prebuilt(); p != nil {
+ return p.UsePrebuilt()
+ }
+ }
+ return true
+}
+
func (b *bootJarsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
config := ctx.Config()
if config.SkipBootJarsCheck() {
return
}
- // Populate a map from module name to APEX from the boot jars. If there is a problem
- // such as duplicate modules then fail and return immediately.
+ // Populate a map from module name to APEX from the boot jars. If there is a
+ // problem such as duplicate modules then fail and return immediately. Note
+ // that both module and APEX names are tracked by base names here, so we need
+ // to be careful to remove "prebuilt_" prefixes when comparing them with
+ // actual modules and APEX bundles.
moduleToApex := make(map[string]string)
if !populateMapFromConfiguredJarList(ctx, moduleToApex, config.NonUpdatableBootJars(), "BootJars") ||
!populateMapFromConfiguredJarList(ctx, moduleToApex, config.UpdatableBootJars(), "UpdatableBootJars") {
@@ -69,10 +91,14 @@ func (b *bootJarsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
// Scan all the modules looking for the module/apex variants corresponding to the
// boot jars.
ctx.VisitAllModules(func(module android.Module) {
- name := ctx.ModuleName(module)
+ if !isActiveModule(module) {
+ return
+ }
+
+ name := android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName(module))
if apex, ok := moduleToApex[name]; ok {
apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
- if (apex == "platform" && apexInfo.IsForPlatform()) || apexInfo.InApex(apex) {
+ if (apex == "platform" && apexInfo.IsForPlatform()) || apexInfo.InApexByBaseName(apex) {
// The module name/apex variant should be unique in the system but double check
// just in case something has gone wrong.
if existing, ok := nameToApexVariant[name]; ok {
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 004cbbb5a..36d0d3017 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -35,6 +35,13 @@ import (
//
// Changes:
// 1) dex_bootjars is now a singleton module and not a plain singleton.
+// 2) Boot images are now represented by the boot_image module type.
+// 3) The art boot image is called "art-boot-image", the framework boot image is called
+// "framework-boot-image".
+// 4) They are defined in art/build/boot/Android.bp and frameworks/base/boot/Android.bp
+// respectively.
+// 5) Each boot_image retrieves the appropriate boot image configuration from the map returned by
+// genBootImageConfigs() using the image_name specified in the boot_image module.
// =================================================================================================
// This comment describes:
@@ -479,7 +486,7 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul
// A platform variant is required but this is for an apex so ignore it.
return -1, nil
}
- } else if !android.InList(requiredApex, apexInfo.InApexes) {
+ } else if !apexInfo.InApexByBaseName(requiredApex) {
// An apex variant for a specific apex is required but this is the wrong apex.
return -1, nil
}
@@ -489,7 +496,7 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul
switch image.name {
case artBootImageName:
- if len(apexInfo.InApexes) > 0 && allHavePrefix(apexInfo.InApexes, "com.android.art") {
+ if apexInfo.InApexByBaseName("com.android.art") || apexInfo.InApexByBaseName("com.android.art.debug") || apexInfo.InApexByBaseName("com.android.art,testing") {
// 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
@@ -516,21 +523,17 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul
return index, jar.DexJarBuildPath()
}
-func allHavePrefix(list []string, prefix string) bool {
- for _, s := range list {
- if s != prefix && !strings.HasPrefix(s, prefix+".") {
- return false
- }
- }
- return true
-}
-
// buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image.
func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig {
// Collect dex jar paths for the boot image modules.
// This logic is tested in the apex package to avoid import cycle apex <-> java.
bootDexJars := make(android.Paths, image.modules.Len())
+
ctx.VisitAllModules(func(module android.Module) {
+ if !isActiveModule(module) {
+ return
+ }
+
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",
@@ -860,6 +863,9 @@ func updatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConf
// Collect `permitted_packages` for updatable boot jars.
var updatablePackages []string
ctx.VisitAllModules(func(module android.Module) {
+ if !isActiveModule(module) {
+ return
+ }
if j, ok := module.(PermittedPackagesForUpdatableBootJars); ok {
name := ctx.ModuleName(module)
if i := android.IndexList(name, updatableModules); i != -1 {
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 0ffbaaa40..1e90149ea 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -15,12 +15,14 @@
package java
import (
+ "fmt"
"strconv"
"strings"
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/genrule"
)
func init() {
@@ -35,6 +37,12 @@ type prebuiltApisProperties struct {
// list of api version directories
Api_dirs []string
+ // The next API directory can optionally point to a directory where
+ // files incompatibility-tracking files are stored for the current
+ // "in progress" API. Each module present in one of the api_dirs will have
+ // a <module>-incompatibilities.api.<scope>.latest module created.
+ Next_api_dir *string
+
// The sdk_version of java_import modules generated based on jar files.
// Defaults to "current"
Imports_sdk_version *string
@@ -98,28 +106,46 @@ func createImport(mctx android.LoadHookContext, module, scope, apiver, path, sdk
mctx.CreateModule(ImportFactory, &props)
}
-func createFilegroup(mctx android.LoadHookContext, module string, scope string, apiver string, path string) {
- fgName := module + ".api." + scope + "." + apiver
+func createFilegroup(mctx android.LoadHookContext, name string, path string) {
filegroupProps := struct {
Name *string
Srcs []string
}{}
- filegroupProps.Name = proptools.StringPtr(fgName)
+ filegroupProps.Name = proptools.StringPtr(name)
filegroupProps.Srcs = []string{path}
mctx.CreateModule(android.FileGroupFactory, &filegroupProps)
}
+func createEmptyFile(mctx android.LoadHookContext, name string) {
+ props := struct {
+ Name *string
+ Cmd *string
+ Out []string
+ }{}
+ props.Name = proptools.StringPtr(name)
+ props.Out = []string{name}
+ props.Cmd = proptools.StringPtr("touch $(genDir)/" + name)
+ mctx.CreateModule(genrule.GenRuleFactory, &props)
+}
+
func getPrebuiltFiles(mctx android.LoadHookContext, p *prebuiltApis, name string) []string {
- mydir := mctx.ModuleDir() + "/"
var files []string
for _, apiver := range p.properties.Api_dirs {
- for _, scope := range []string{"public", "system", "test", "core", "module-lib", "system-server"} {
- vfiles, err := mctx.GlobWithDeps(mydir+apiver+"/"+scope+"/"+name, nil)
- if err != nil {
- mctx.ModuleErrorf("failed to glob %s files under %q: %s", name, mydir+apiver+"/"+scope, err)
- }
- files = append(files, vfiles...)
+ files = append(files, getPrebuiltFilesInSubdir(mctx, apiver, name)...)
+ }
+ return files
+}
+
+func getPrebuiltFilesInSubdir(mctx android.LoadHookContext, subdir string, name string) []string {
+ var files []string
+ dir := mctx.ModuleDir() + "/" + subdir
+ for _, scope := range []string{"public", "system", "test", "core", "module-lib", "system-server"} {
+ glob := fmt.Sprintf("%s/%s/%s", dir, scope, name)
+ vfiles, err := mctx.GlobWithDeps(glob, nil)
+ if err != nil {
+ mctx.ModuleErrorf("failed to glob %s files under %q: %s", name, dir+"/"+scope, err)
}
+ files = append(files, vfiles...)
}
return files
}
@@ -181,11 +207,14 @@ func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) {
// Create filegroups for all (<module>, <scope, <version>) triplets,
// and a "latest" filegroup variant for each (<module>, <scope>) pair
+ moduleName := func(module, scope, version string) string {
+ return module + ".api." + scope + "." + version
+ }
m := make(map[string]latestApiInfo)
for _, f := range files {
localPath := strings.TrimPrefix(f, mydir)
module, apiver, scope := parseApiFilePath(mctx, localPath)
- createFilegroup(mctx, module, scope, apiver, localPath)
+ createFilegroup(mctx, moduleName(module, scope, apiver), localPath)
version, err := strconv.Atoi(apiver)
if err != nil {
@@ -193,20 +222,52 @@ func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) {
return
}
- key := module + "." + scope
- info, ok := m[key]
- if !ok {
- m[key] = latestApiInfo{module, scope, version, localPath}
- } else if version > info.version {
- info.version = version
- info.path = localPath
- m[key] = info
+ // Track latest version of each module/scope, except for incompatibilities
+ if !strings.HasSuffix(module, "incompatibilities") {
+ key := module + "." + scope
+ info, ok := m[key]
+ if !ok {
+ m[key] = latestApiInfo{module, scope, version, localPath}
+ } else if version > info.version {
+ info.version = version
+ info.path = localPath
+ m[key] = info
+ }
}
}
+
// Sort the keys in order to make build.ninja stable
for _, k := range android.SortedStringKeys(m) {
info := m[k]
- createFilegroup(mctx, info.module, info.scope, "latest", info.path)
+ name := moduleName(info.module, info.scope, "latest")
+ createFilegroup(mctx, name, info.path)
+ }
+
+ // Create incompatibilities tracking files for all modules, if we have a "next" api.
+ if nextApiDir := String(p.properties.Next_api_dir); nextApiDir != "" {
+ files := getPrebuiltFilesInSubdir(mctx, nextApiDir, "api/*incompatibilities.txt")
+ incompatibilities := make(map[string]bool)
+ for _, f := range files {
+ localPath := strings.TrimPrefix(f, mydir)
+ module, _, scope := parseApiFilePath(mctx, localPath)
+
+ // Figure out which module is referenced by this file. Special case for "android".
+ referencedModule := strings.TrimSuffix(module, "incompatibilities")
+ referencedModule = strings.TrimSuffix(referencedModule, "-")
+ if referencedModule == "" {
+ referencedModule = "android"
+ }
+
+ createFilegroup(mctx, moduleName(referencedModule+"-incompatibilities", scope, "latest"), localPath)
+
+ incompatibilities[referencedModule+"."+scope] = true
+ }
+ // Create empty incompatibilities files for remaining modules
+ for _, k := range android.SortedStringKeys(m) {
+ if _, ok := incompatibilities[k]; !ok {
+ createEmptyFile(mctx, moduleName(m[k].module+"-incompatibilities", m[k].scope, "latest"))
+ }
+ }
}
}
diff --git a/java/testing.go b/java/testing.go
index 0b1f2d137..31ff47ff4 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -107,6 +107,7 @@ func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
RegisterAppBuildComponents(ctx)
RegisterAppImportBuildComponents(ctx)
RegisterAppSetBuildComponents(ctx)
+ RegisterBootImageBuildComponents(ctx)
RegisterDexpreoptBootJarsComponents(ctx)
RegisterDocsBuildComponents(ctx)
RegisterGenRuleBuildComponents(ctx)
@@ -218,6 +219,16 @@ func GatherRequiredDepsForTest() string {
dex_bootjars {
name: "dex_bootjars",
}
+
+ boot_image {
+ name: "art-boot-image",
+ image_name: "art",
+ }
+
+ boot_image {
+ name: "framework-boot-image",
+ image_name: "boot",
+ }
`
return bp
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 030772722..1a286f738 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -18,6 +18,7 @@ import (
"path/filepath"
"android/soong/android"
+ "android/soong/cc"
)
type AndroidMkContext interface {
@@ -85,7 +86,8 @@ func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.Andr
}
func (test *testDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
- test.binaryDecorator.AndroidMk(ctx, ret)
+ ctx.SubAndroidMk(ret, test.binaryDecorator)
+
ret.Class = "NATIVE_TESTS"
ret.ExtraEntries = append(ret.ExtraEntries, func(entries *android.AndroidMkEntries) {
entries.AddCompatibilityTestSuites(test.Properties.Test_suites...)
@@ -95,7 +97,8 @@ func (test *testDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidM
entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(test.Properties.Auto_gen_config, true))
entries.SetBoolIfTrue("LOCAL_IS_UNIT_TEST", Bool(test.Properties.Test_options.Unit_test))
})
- // TODO(chh): add test data with androidMkWriteTestData(test.data, ctx, ret)
+
+ cc.AndroidMkWriteTestData(test.data, ret)
}
func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
diff --git a/rust/rust_test.go b/rust/rust_test.go
index fc7f47e08..abc9af9b1 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -116,6 +116,7 @@ func (tctx *testRustCtx) useMockedFs() {
"foo.proto": nil,
"liby.so": nil,
"libz.so": nil,
+ "data.txt": nil,
}
}
diff --git a/rust/test.go b/rust/test.go
index 35e04fff6..92b486070 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -43,6 +43,10 @@ type TestProperties struct {
// installed into.
Test_suites []string `android:"arch_variant"`
+ // list of files or filegroup modules that provide data that should be installed alongside
+ // the test
+ Data []string `android:"path,arch_variant"`
+
// Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
// explicitly.
@@ -62,6 +66,12 @@ type testDecorator struct {
*binaryDecorator
Properties TestProperties
testConfig android.Path
+
+ data []android.DataPath
+}
+
+func (test *testDecorator) dataPaths() []android.DataPath {
+ return test.data
}
func (test *testDecorator) nativeCoverage() bool {
@@ -89,7 +99,6 @@ func NewRustTest(hod android.HostOrDeviceSupported) (*Module, *testDecorator) {
}
module.compiler = test
- module.AddProperties(&test.Properties)
return module, test
}
@@ -105,6 +114,12 @@ func (test *testDecorator) install(ctx ModuleContext) {
nil,
test.Properties.Auto_gen_config)
+ dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data)
+
+ for _, dataSrcPath := range dataSrcPaths {
+ test.data = append(test.data, android.DataPath{SrcPath: dataSrcPath})
+ }
+
// default relative install path is module name
if !Bool(test.Properties.No_named_install_directory) {
test.baseCompiler.relative = ctx.ModuleName()
diff --git a/rust/test_test.go b/rust/test_test.go
index fea2ad059..892761a07 100644
--- a/rust/test_test.go
+++ b/rust/test_test.go
@@ -26,6 +26,7 @@ func TestRustTest(t *testing.T) {
rust_test_host {
name: "my_test",
srcs: ["foo.rs"],
+ data: ["data.txt"],
}`)
testingModule := ctx.ModuleForTests("my_test", "linux_glibc_x86_64")
@@ -34,6 +35,12 @@ func TestRustTest(t *testing.T) {
if !strings.Contains(outPath, expectedOut) {
t.Errorf("wrong output path: %v; expected: %v", outPath, expectedOut)
}
+
+ dataPaths := testingModule.Module().(*Module).compiler.(*testDecorator).dataPaths()
+ if len(dataPaths) != 1 {
+ t.Errorf("expected exactly one test data file. test data files: [%s]", dataPaths)
+ return
+ }
}
func TestRustTestLinkage(t *testing.T) {