Merge "Store build targets in the soong metrics."
diff --git a/android/arch.go b/android/arch.go
index 273c02b..54242e5 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -2005,16 +2005,37 @@
osToProp := ArchVariantProperties{}
archOsToProp := ArchVariantProperties{}
+
+ var linuxStructs, bionicStructs []reflect.Value
+ var ok bool
+
+ linuxStructs, ok = getTargetStructs(ctx, archProperties, "Linux")
+ if !ok {
+ linuxStructs = make([]reflect.Value, 0)
+ }
+ bionicStructs, ok = getTargetStructs(ctx, archProperties, "Bionic")
+ if !ok {
+ bionicStructs = make([]reflect.Value, 0)
+ }
+
// For android, linux, ...
for _, os := range osTypeList {
if os == CommonOS {
// It looks like this OS value is not used in Blueprint files
continue
}
- osStructs, ok := getTargetStructs(ctx, archProperties, os.Field)
+ osStructs := make([]reflect.Value, 0)
+ osSpecificStructs, ok := getTargetStructs(ctx, archProperties, os.Field)
if ok {
- osToProp[os.Name] = mergeStructs(ctx, osStructs, propertySet)
+ osStructs = append(osStructs, osSpecificStructs...)
}
+ if os.Linux() {
+ osStructs = append(osStructs, linuxStructs...)
+ }
+ if os.Bionic() {
+ osStructs = append(osStructs, bionicStructs...)
+ }
+ osToProp[os.Name] = mergeStructs(ctx, osStructs, propertySet)
// For arm, x86, ...
for _, arch := range osArchTypeMap[os] {
@@ -2048,15 +2069,9 @@
archOsToProp[targetName] = mergeStructs(ctx, osArchStructs, propertySet)
}
}
+
axisToProps[bazel.OsConfigurationAxis] = osToProp
axisToProps[bazel.OsArchConfigurationAxis] = archOsToProp
-
- bionicStructs, ok := getTargetStructs(ctx, archProperties, "Bionic")
- if ok {
- axisToProps[bazel.BionicConfigurationAxis] = map[string]interface{}{
- "bionic": mergeStructs(ctx, bionicStructs, propertySet)}
- }
-
return axisToProps
}
diff --git a/android/bazel.go b/android/bazel.go
index f5ae453..6aba759 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -182,8 +182,11 @@
"external/boringssl": Bp2BuildDefaultTrueRecursively,
"external/brotli": Bp2BuildDefaultTrue,
"external/fmtlib": Bp2BuildDefaultTrueRecursively,
+ "external/googletest/googletest": Bp2BuildDefaultTrueRecursively,
+ "external/google-benchmark": Bp2BuildDefaultTrueRecursively,
"external/gwp_asan": Bp2BuildDefaultTrueRecursively,
"external/jemalloc_new": Bp2BuildDefaultTrueRecursively,
+ "external/jsoncpp": Bp2BuildDefaultTrueRecursively,
"external/libcap": Bp2BuildDefaultTrueRecursively,
"external/libcxx": Bp2BuildDefaultTrueRecursively,
"external/libcxxabi": Bp2BuildDefaultTrueRecursively,
@@ -206,8 +209,11 @@
"system/core/libcrypto_utils": Bp2BuildDefaultTrueRecursively,
"system/core/libcutils": Bp2BuildDefaultTrueRecursively,
"system/core/libprocessgroup": Bp2BuildDefaultTrue,
+ "system/core/libprocessgroup/cgrouprc": Bp2BuildDefaultTrue,
+ "system/core/libprocessgroup/cgrouprc_format": Bp2BuildDefaultTrue,
"system/core/property_service/libpropertyinfoparser": Bp2BuildDefaultTrueRecursively,
"system/libbase": Bp2BuildDefaultTrueRecursively,
+ "system/libziparchive": Bp2BuildDefaultTrueRecursively,
"system/logging/liblog": Bp2BuildDefaultTrueRecursively,
"system/sepolicy/apex": Bp2BuildDefaultTrueRecursively,
"system/timezone/apex": Bp2BuildDefaultTrueRecursively,
@@ -216,33 +222,9 @@
// Per-module denylist to always opt modules out of both bp2build and mixed builds.
bp2buildModuleDoNotConvertList = []string{
- // Things that transitively depend on unconverted libc_* modules.
- "libbionic_spawn_benchmark", // http://b/186824595, cc_library_static, depends on //external/google-benchmark (http://b/186822740)
- // also depends on //system/logging/liblog:liblog (http://b/186822772)
+ "libc_malloc_debug", // depends on libunwindstack, which depends on unsupported module art_cc_library_statics
- "libc_malloc_debug", // http://b/186824339, cc_library_static, depends on //system/libbase:libbase (http://b/186823646)
- "libc_malloc_debug_backtrace", // http://b/186824112, cc_library_static, depends on //external/libcxxabi:libc++demangle (http://b/186823773)
-
- //"libcutils", // http://b/186827426, cc_library, depends on //system/core/libprocessgroup:libprocessgroup_headers (http://b/186826841)
- //"libcutils_sockets", // http://b/186826853, cc_library, depends on //system/libbase:libbase (http://b/186826479)
-
- "liblinker_debuggerd_stub", // http://b/186824327, cc_library_static, depends on //external/zlib:libz (http://b/186823782)
- // also depends on //system/libziparchive:libziparchive (http://b/186823656)
- // also depends on //system/logging/liblog:liblog (http://b/186822772)
- "liblinker_main", // http://b/186825989, cc_library_static, depends on //external/zlib:libz (http://b/186823782)
- // also depends on //system/libziparchive:libziparchive (http://b/186823656)
- // also depends on//system/logging/liblog:liblog (http://b/186822772)
- "liblinker_malloc", // http://b/186826466, cc_library_static, depends on //external/zlib:libz (http://b/186823782)
- // also depends on //system/libziparchive:libziparchive (http://b/186823656)
- // also depends on //system/logging/liblog:liblog (http://b/186822772)
- "libc_ndk", // http://b/187013218, cc_library_static, depends on //bionic/libm:libm (http://b/183064661)
- "libc_malloc_hooks", // http://b/187016307, cc_library, ld.lld: error: undefined symbol: __malloc_hook
-
- // http://b/186823769: Needs C++ STL support, includes from unconverted standard libraries in //external/libcxx
- // c++_static
- "libbase_ndk", // http://b/186826477, cc_library, no such target '//build/bazel/platforms/os:darwin' when --platforms //build/bazel/platforms:android_x86 is added
- // libcxx
- "libBionicBenchmarksUtils", // cc_library_static, fatal error: 'map' file not found, from libcxx
+ "libbase_ndk", // http://b/186826477, fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
"libprotobuf-python", // contains .proto sources
"libprotobuf-internal-protos", // we don't handle path property for fileegroups
@@ -253,11 +235,7 @@
"gwp_asan_crash_handler", // cc_library, ld.lld: error: undefined symbol: memset
- //system/core/libprocessgroup/...
- "libprocessgroup", // depends on //system/core/libprocessgroup/cgrouprc:libcgrouprc
-
- //external/brotli/...
- "brotli-fuzzer-corpus", // "declared output 'external/brotli/c/fuzz/73231c6592f195ffd41100b8706d1138ff6893b9' was not created by genrule"
+ "brotli-fuzzer-corpus", // b/202015218: outputs are in location incompatible with bazel genrule handling.
// //external/libcap/...
"libcap", // http://b/198595332, depends on _makenames, a cc_binary
@@ -270,7 +248,7 @@
"libjemalloc5_unittest",
// APEX support
- "com.android.runtime", // http://b/194746715, apex, depends on 'libc_malloc_debug' and 'libc_malloc_hooks'
+ "com.android.runtime", // http://b/194746715, apex, depends on 'libc_malloc_debug'
"libadb_crypto", // Depends on libadb_protos
"libadb_crypto_static", // Depends on libadb_protos_static
@@ -285,6 +263,9 @@
"libadb_protos_static", // b/200601772: Requires cc_library proto support
"libadb_protos", // b/200601772: Requires cc_library proto support
"libapp_processes_protos_lite", // b/200601772: Requires cc_library proto support
+
+ "libgtest_ndk_c++", // b/201816222: Requires sdk_version support.
+ "libgtest_main_ndk_c++", // b/201816222: Requires sdk_version support.
}
// Per-module denylist of cc_library modules to only generate the static
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 2241255..6648a2f 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -815,7 +815,7 @@
if len(buildStatement.OutputPaths) > 0 {
cmd.Text("rm -f")
for _, outputPath := range buildStatement.OutputPaths {
- cmd.Text(PathForBazelOut(ctx, outputPath).String())
+ cmd.Text(outputPath)
}
cmd.Text("&&")
}
diff --git a/android/config.go b/android/config.go
index e7ebdef..c8d7cfd 100644
--- a/android/config.go
+++ b/android/config.go
@@ -854,11 +854,6 @@
return Bool(c.productVariables.Always_use_prebuilt_sdks)
}
-// Returns true if the boot jars check should be skipped.
-func (c *config) SkipBootJarsCheck() bool {
- return Bool(c.productVariables.Skip_boot_jars_check)
-}
-
func (c *config) MinimizeJavaDebugInfo() bool {
return Bool(c.productVariables.MinimizeJavaDebugInfo) && !Bool(c.productVariables.Eng)
}
diff --git a/android/filegroup.go b/android/filegroup.go
index 4db165f..2cf5567 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -72,7 +72,7 @@
Bzl_load_location: "//build/bazel/rules:filegroup.bzl",
}
- ctx.CreateBazelTargetModule(fg.Name(), props, attrs)
+ ctx.CreateBazelTargetModule(props, CommonAttributes{Name: fg.Name()}, attrs)
}
type fileGroupProperties struct {
diff --git a/android/module.go b/android/module.go
index c9b01a0..327e6ae 100644
--- a/android/module.go
+++ b/android/module.go
@@ -852,6 +852,16 @@
UnconvertedBp2buildDeps []string `blueprint:"mutated"`
}
+// CommonAttributes represents the common Bazel attributes from which properties
+// in `commonProperties` are translated/mapped; such properties are annotated in
+// a list their corresponding attribute. It is embedded within `bp2buildInfo`.
+type CommonAttributes struct {
+ // Soong nameProperties -> Bazel name
+ Name string
+ // Data mapped from: Required
+ Data bazel.LabelListAttribute
+}
+
type distProperties struct {
// configuration to distribute output files from this module to the distribution
// directory (default: $OUT/dist, configurable with $DIST_DIR)
@@ -1072,6 +1082,34 @@
m.base().commonProperties.CreateCommonOSVariant = true
}
+func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutatorContext) {
+ // Assert passed-in attributes include Name
+ name := attrs.Name
+ if len(name) == 0 {
+ ctx.ModuleErrorf("CommonAttributes in fillCommonBp2BuildModuleAttrs expects a `.Name`!")
+ }
+
+ mod := ctx.Module().base()
+ props := &mod.commonProperties
+
+ depsToLabelList := func(deps []string) bazel.LabelListAttribute {
+ return bazel.MakeLabelListAttribute(BazelLabelForModuleDeps(ctx, deps))
+ }
+
+ data := &attrs.Data
+
+ required := depsToLabelList(props.Required)
+ archVariantProps := mod.GetArchVariantProperties(ctx, &commonProperties{})
+ for axis, configToProps := range archVariantProps {
+ for config, _props := range configToProps {
+ if archProps, ok := _props.(*commonProperties); ok {
+ required.SetSelectValue(axis, config, depsToLabelList(archProps.Required).Value)
+ }
+ }
+ }
+ data.Append(required)
+}
+
// A ModuleBase object contains the properties that are common to all Android
// modules. It should be included as an anonymous field in every module
// struct definition. InitAndroidModule should then be called from the module's
@@ -1183,15 +1221,15 @@
// A struct containing all relevant information about a Bazel target converted via bp2build.
type bp2buildInfo struct {
- Name string
- Dir string
- BazelProps bazel.BazelTargetModuleProperties
- Attrs interface{}
+ Dir string
+ BazelProps bazel.BazelTargetModuleProperties
+ CommonAttrs CommonAttributes
+ Attrs interface{}
}
// TargetName returns the Bazel target name of a bp2build converted target.
func (b bp2buildInfo) TargetName() string {
- return b.Name
+ return b.CommonAttrs.Name
}
// TargetPackage returns the Bazel package of a bp2build converted target.
@@ -1211,8 +1249,8 @@
}
// BazelAttributes returns the Bazel attributes of a bp2build converted target.
-func (b bp2buildInfo) BazelAttributes() interface{} {
- return b.Attrs
+func (b bp2buildInfo) BazelAttributes() []interface{} {
+ return []interface{}{&b.CommonAttrs, b.Attrs}
}
func (m *ModuleBase) addBp2buildInfo(info bp2buildInfo) {
diff --git a/android/mutator.go b/android/mutator.go
index b361c51..4b37377 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -15,10 +15,11 @@
package android
import (
- "android/soong/bazel"
"reflect"
"sync"
+ "android/soong/bazel"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -268,7 +269,7 @@
// factory method, just like in CreateModule, but also requires
// BazelTargetModuleProperties containing additional metadata for the
// bp2build codegenerator.
- CreateBazelTargetModule(string, bazel.BazelTargetModuleProperties, interface{})
+ CreateBazelTargetModule(bazel.BazelTargetModuleProperties, CommonAttributes, interface{})
}
type topDownMutatorContext struct {
@@ -514,17 +515,18 @@
}
func (t *topDownMutatorContext) CreateBazelTargetModule(
- name string,
bazelProps bazel.BazelTargetModuleProperties,
+ commonAttrs CommonAttributes,
attrs interface{}) {
-
+ commonAttrs.fillCommonBp2BuildModuleAttrs(t)
+ mod := t.Module()
info := bp2buildInfo{
- Name: name,
- Dir: t.OtherModuleDir(t.Module()),
- BazelProps: bazelProps,
- Attrs: attrs,
+ Dir: t.OtherModuleDir(mod),
+ BazelProps: bazelProps,
+ CommonAttrs: commonAttrs,
+ Attrs: attrs,
}
- t.Module().base().addBp2buildInfo(info)
+ mod.base().addBp2buildInfo(info)
}
func (t *topDownMutatorContext) AppendProperties(props ...interface{}) {
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 6605869..c9a9ddd 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -769,16 +769,25 @@
paths Paths
}
+func checkPathNotNil(path Path) {
+ if path == nil {
+ panic("rule_builder paths cannot be nil")
+ }
+}
+
func (c *RuleBuilderCommand) addInput(path Path) string {
+ checkPathNotNil(path)
c.inputs = append(c.inputs, path)
return c.PathForInput(path)
}
func (c *RuleBuilderCommand) addImplicit(path Path) {
+ checkPathNotNil(path)
c.implicits = append(c.implicits, path)
}
func (c *RuleBuilderCommand) addOrderOnly(path Path) {
+ checkPathNotNil(path)
c.orderOnlys = append(c.orderOnlys, path)
}
@@ -1004,19 +1013,23 @@
// Tool adds the specified tool path to the command line. The path will be also added to the dependencies returned by
// RuleBuilder.Tools.
func (c *RuleBuilderCommand) Tool(path Path) *RuleBuilderCommand {
+ checkPathNotNil(path)
c.tools = append(c.tools, path)
return c.Text(c.PathForTool(path))
}
// Tool adds the specified tool path to the dependencies returned by RuleBuilder.Tools.
func (c *RuleBuilderCommand) ImplicitTool(path Path) *RuleBuilderCommand {
+ checkPathNotNil(path)
c.tools = append(c.tools, path)
return c
}
// Tool adds the specified tool path to the dependencies returned by RuleBuilder.Tools.
func (c *RuleBuilderCommand) ImplicitTools(paths Paths) *RuleBuilderCommand {
- c.tools = append(c.tools, paths...)
+ for _, path := range paths {
+ c.ImplicitTool(path)
+ }
return c
}
@@ -1093,6 +1106,7 @@
// Validation adds the specified input path to the validation dependencies by
// RuleBuilder.Validations without modifying the command line.
func (c *RuleBuilderCommand) Validation(path Path) *RuleBuilderCommand {
+ checkPathNotNil(path)
c.validations = append(c.validations, path)
return c
}
@@ -1100,13 +1114,16 @@
// Validations adds the specified input paths to the validation dependencies by
// RuleBuilder.Validations without modifying the command line.
func (c *RuleBuilderCommand) Validations(paths Paths) *RuleBuilderCommand {
- c.validations = append(c.validations, paths...)
+ for _, path := range paths {
+ c.Validation(path)
+ }
return c
}
// Output adds the specified output path to the command line. The path will also be added to the outputs returned by
// RuleBuilder.Outputs.
func (c *RuleBuilderCommand) Output(path WritablePath) *RuleBuilderCommand {
+ checkPathNotNil(path)
c.outputs = append(c.outputs, path)
return c.Text(c.PathForOutput(path))
}
@@ -1133,6 +1150,7 @@
// line, and causes RuleBuilder.Build file to set the depfile flag for ninja. If multiple depfiles are added to
// commands in a single RuleBuilder then RuleBuilder.Build will add an extra command to merge the depfiles together.
func (c *RuleBuilderCommand) DepFile(path WritablePath) *RuleBuilderCommand {
+ checkPathNotNil(path)
c.depFiles = append(c.depFiles, path)
return c.Text(c.PathForOutput(path))
}
@@ -1155,6 +1173,7 @@
// will be a symlink instead of a regular file. Does not modify the command
// line.
func (c *RuleBuilderCommand) ImplicitSymlinkOutput(path WritablePath) *RuleBuilderCommand {
+ checkPathNotNil(path)
c.symlinkOutputs = append(c.symlinkOutputs, path)
return c.ImplicitOutput(path)
}
@@ -1172,6 +1191,7 @@
// SymlinkOutput declares the specified path as an output that will be a symlink
// instead of a regular file. Modifies the command line.
func (c *RuleBuilderCommand) SymlinkOutput(path WritablePath) *RuleBuilderCommand {
+ checkPathNotNil(path)
c.symlinkOutputs = append(c.symlinkOutputs, path)
return c.Output(path)
}
diff --git a/apex/apex.go b/apex/apex.go
index 5294b6c..0a2e35b 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -3325,5 +3325,5 @@
Bzl_load_location: "//build/bazel/rules:apex.bzl",
}
- ctx.CreateBazelTargetModule(module.Name(), props, attrs)
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 420489e..5eb7acf 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -5058,8 +5058,9 @@
annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
metadata: "my-bootclasspath-fragment/metadata.csv",
index: "my-bootclasspath-fragment/index.csv",
- stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
- all_flags: "my-bootclasspath-fragment/all-flags.csv",
+ signature_patterns: "my-bootclasspath-fragment/signature-patterns.csv",
+ filtered_stub_flags: "my-bootclasspath-fragment/filtered-stub-flags.csv",
+ filtered_flags: "my-bootclasspath-fragment/filtered-flags.csv",
},
}
@@ -5109,8 +5110,9 @@
annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
metadata: "my-bootclasspath-fragment/metadata.csv",
index: "my-bootclasspath-fragment/index.csv",
- stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
- all_flags: "my-bootclasspath-fragment/all-flags.csv",
+ signature_patterns: "my-bootclasspath-fragment/signature-patterns.csv",
+ filtered_stub_flags: "my-bootclasspath-fragment/filtered-stub-flags.csv",
+ filtered_flags: "my-bootclasspath-fragment/filtered-flags.csv",
},
}
@@ -5238,8 +5240,9 @@
annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
metadata: "my-bootclasspath-fragment/metadata.csv",
index: "my-bootclasspath-fragment/index.csv",
- stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
- all_flags: "my-bootclasspath-fragment/all-flags.csv",
+ signature_patterns: "my-bootclasspath-fragment/signature-patterns.csv",
+ filtered_stub_flags: "my-bootclasspath-fragment/filtered-stub-flags.csv",
+ filtered_flags: "my-bootclasspath-fragment/filtered-flags.csv",
},
}
@@ -5324,8 +5327,9 @@
annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
metadata: "my-bootclasspath-fragment/metadata.csv",
index: "my-bootclasspath-fragment/index.csv",
- stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
- all_flags: "my-bootclasspath-fragment/all-flags.csv",
+ signature_patterns: "my-bootclasspath-fragment/signature-patterns.csv",
+ filtered_stub_flags: "my-bootclasspath-fragment/filtered-stub-flags.csv",
+ filtered_flags: "my-bootclasspath-fragment/filtered-flags.csv",
},
}
@@ -5408,8 +5412,9 @@
annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
metadata: "my-bootclasspath-fragment/metadata.csv",
index: "my-bootclasspath-fragment/index.csv",
- stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
- all_flags: "my-bootclasspath-fragment/all-flags.csv",
+ signature_patterns: "my-bootclasspath-fragment/signature-patterns.csv",
+ filtered_stub_flags: "my-bootclasspath-fragment/filtered-stub-flags.csv",
+ filtered_flags: "my-bootclasspath-fragment/filtered-flags.csv",
},
}
@@ -7441,8 +7446,9 @@
annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
metadata: "my-bootclasspath-fragment/metadata.csv",
index: "my-bootclasspath-fragment/index.csv",
- stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
- all_flags: "my-bootclasspath-fragment/all-flags.csv",
+ signature_patterns: "my-bootclasspath-fragment/signature-patterns.csv",
+ filtered_stub_flags: "my-bootclasspath-fragment/filtered-stub-flags.csv",
+ filtered_flags: "my-bootclasspath-fragment/filtered-flags.csv",
},
}
diff --git a/apex/key.go b/apex/key.go
index 468bb8a..e2695d7 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -240,5 +240,5 @@
Bzl_load_location: "//build/bazel/rules:apex_key.bzl",
}
- ctx.CreateBazelTargetModule(module.Name(), props, attrs)
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
}
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index d8a4a7a..06c39ee 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -168,6 +168,76 @@
android.AssertArrayString(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/filtered-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop())
}
+// TestPlatformBootclasspath_LegacyPrebuiltFragment verifies that the
+// prebuilt_bootclasspath_fragment falls back to using the complete stub-flags/all-flags if the
+// filtered files are not provided.
+//
+// TODO: Remove once all prebuilts use the filtered_... properties.
+func TestPlatformBootclasspath_LegacyPrebuiltFragment(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ java.FixtureConfigureApexBootJars("myapex:foo"),
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ ).RunTestWithBp(t, `
+ prebuilt_apex {
+ name: "myapex",
+ src: "myapex.apex",
+ exported_bootclasspath_fragments: ["mybootclasspath-fragment"],
+ }
+
+ // A prebuilt java_sdk_library_import that is not preferred by default but will be preferred
+ // because AlwaysUsePrebuiltSdks() is true.
+ java_sdk_library_import {
+ name: "foo",
+ prefer: false,
+ shared_library: false,
+ permitted_packages: ["foo"],
+ public: {
+ jars: ["sdk_library/public/foo-stubs.jar"],
+ stub_srcs: ["sdk_library/public/foo_stub_sources"],
+ current_api: "sdk_library/public/foo.txt",
+ removed_api: "sdk_library/public/foo-removed.txt",
+ sdk_version: "current",
+ },
+ apex_available: ["myapex"],
+ }
+
+ prebuilt_bootclasspath_fragment {
+ name: "mybootclasspath-fragment",
+ apex_available: [
+ "myapex",
+ ],
+ contents: [
+ "foo",
+ ],
+ hidden_api: {
+ stub_flags: "prebuilt-stub-flags.csv",
+ annotation_flags: "prebuilt-annotation-flags.csv",
+ metadata: "prebuilt-metadata.csv",
+ index: "prebuilt-index.csv",
+ all_flags: "prebuilt-all-flags.csv",
+ },
+ }
+
+ platform_bootclasspath {
+ name: "myplatform-bootclasspath",
+ fragments: [
+ {
+ apex: "myapex",
+ module:"mybootclasspath-fragment",
+ },
+ ],
+ }
+`,
+ )
+
+ pbcp := result.Module("myplatform-bootclasspath", "android_common")
+ info := result.ModuleProvider(pbcp, java.MonolithicHiddenAPIInfoProvider).(java.MonolithicHiddenAPIInfo)
+
+ android.AssertArrayString(t, "stub flags", []string{"prebuilt-stub-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop())
+ android.AssertArrayString(t, "all flags", []string{"prebuilt-all-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop())
+}
+
func TestPlatformBootclasspathDependencies(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
index dc682fa..412fa0e 100644
--- a/apex/systemserver_classpath_fragment_test.go
+++ b/apex/systemserver_classpath_fragment_test.go
@@ -138,7 +138,7 @@
dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"),
).
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
- `in contents must also be declared in PRODUCT_UPDATABLE_SYSTEM_SERVER_JARS`)).
+ `in contents must also be declared in PRODUCT_APEX_SYSTEM_SERVER_JARS`)).
RunTestWithBp(t, `
apex {
name: "myapex",
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 7aaff9a..e9641e7 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -91,11 +91,6 @@
ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
}
- platformBionicMap = map[string]string{
- "bionic": "//build/bazel/platforms/os:bionic",
- ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
- }
-
platformOsArchMap = map[string]string{
osArchAndroidArm: "//build/bazel/platforms/os_arch:android_arm",
osArchAndroidArm64: "//build/bazel/platforms/os_arch:android_arm64",
@@ -122,7 +117,6 @@
arch
os
osArch
- bionic
productVariables
)
@@ -132,7 +126,6 @@
arch: "arch",
os: "os",
osArch: "arch_os",
- bionic: "bionic",
productVariables: "product_variables",
}[ct]
}
@@ -155,10 +148,6 @@
if _, ok := platformOsArchMap[config]; !ok {
panic(fmt.Errorf("Unknown os+arch: %s", config))
}
- case bionic:
- if _, ok := platformBionicMap[config]; !ok {
- panic(fmt.Errorf("Unknown for %s: %s", ct.String(), config))
- }
case productVariables:
// do nothing
default:
@@ -178,8 +167,6 @@
return platformOsMap[config]
case osArch:
return platformOsArchMap[config]
- case bionic:
- return platformBionicMap[config]
case productVariables:
if config == ConditionsDefaultConfigKey {
return ConditionsDefaultSelectKey
@@ -199,8 +186,6 @@
OsConfigurationAxis = ConfigurationAxis{configurationType: os}
// An axis for arch+os-specific configurations
OsArchConfigurationAxis = ConfigurationAxis{configurationType: osArch}
- // An axis for bionic os-specific configurations
- BionicConfigurationAxis = ConfigurationAxis{configurationType: bionic}
)
// ProductVariableConfigurationAxis returns an axis for the given product variable
diff --git a/bazel/properties.go b/bazel/properties.go
index bd8ef0d..ee32e73 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -264,7 +264,7 @@
switch axis.configurationType {
case noConfig:
la.Value = &value
- case arch, os, osArch, bionic, productVariables:
+ case arch, os, osArch, productVariables:
if la.ConfigurableValues == nil {
la.ConfigurableValues = make(configurableLabels)
}
@@ -280,7 +280,7 @@
switch axis.configurationType {
case noConfig:
return *la.Value
- case arch, os, osArch, bionic, productVariables:
+ case arch, os, osArch, productVariables:
return *la.ConfigurableValues[axis][config]
default:
panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
@@ -337,7 +337,7 @@
switch axis.configurationType {
case noConfig:
ba.Value = value
- case arch, os, osArch, bionic, productVariables:
+ case arch, os, osArch, productVariables:
if ba.ConfigurableValues == nil {
ba.ConfigurableValues = make(configurableBools)
}
@@ -353,7 +353,7 @@
switch axis.configurationType {
case noConfig:
return ba.Value
- case arch, os, osArch, bionic, productVariables:
+ case arch, os, osArch, productVariables:
if v, ok := ba.ConfigurableValues[axis][config]; ok {
return &v
} else {
@@ -459,7 +459,7 @@
switch axis.configurationType {
case noConfig:
lla.Value = list
- case arch, os, osArch, bionic, productVariables:
+ case arch, os, osArch, productVariables:
if lla.ConfigurableValues == nil {
lla.ConfigurableValues = make(configurableLabelLists)
}
@@ -475,7 +475,7 @@
switch axis.configurationType {
case noConfig:
return lla.Value
- case arch, os, osArch, bionic, productVariables:
+ case arch, os, osArch, productVariables:
return lla.ConfigurableValues[axis][config]
default:
panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
@@ -773,7 +773,7 @@
switch axis.configurationType {
case noConfig:
sla.Value = list
- case arch, os, osArch, bionic, productVariables:
+ case arch, os, osArch, productVariables:
if sla.ConfigurableValues == nil {
sla.ConfigurableValues = make(configurableStringLists)
}
@@ -789,7 +789,7 @@
switch axis.configurationType {
case noConfig:
return sla.Value
- case arch, os, osArch, bionic, productVariables:
+ case arch, os, osArch, productVariables:
return sla.ConfigurableValues[axis][config]
default:
panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 4a0eeea..c05a62b 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -411,7 +411,7 @@
TargetPackage() string
BazelRuleClass() string
BazelRuleLoadLocation() string
- BazelAttributes() interface{}
+ BazelAttributes() []interface{}
}
func generateBazelTarget(ctx bpToBuildContext, m bp2buildModule) BazelTarget {
@@ -419,7 +419,8 @@
bzlLoadLocation := m.BazelRuleLoadLocation()
// extract the bazel attributes from the module.
- props := extractModuleProperties([]interface{}{m.BazelAttributes()})
+ attrs := m.BazelAttributes()
+ props := extractModuleProperties(attrs, true)
delete(props.Attrs, "bp2build_available")
@@ -482,14 +483,14 @@
// TODO: this omits properties for blueprint modules (blueprint_go_binary,
// bootstrap_go_binary, bootstrap_go_package), which will have to be handled separately.
if aModule, ok := m.(android.Module); ok {
- return extractModuleProperties(aModule.GetProperties())
+ return extractModuleProperties(aModule.GetProperties(), false)
}
return BazelAttributes{}
}
// Generically extract module properties and types into a map, keyed by the module property name.
-func extractModuleProperties(props []interface{}) BazelAttributes {
+func extractModuleProperties(props []interface{}, checkForDuplicateProperties bool) BazelAttributes {
ret := map[string]string{}
// Iterate over this android.Module's property structs.
@@ -503,6 +504,11 @@
if isStructPtr(propertiesValue.Type()) {
structValue := propertiesValue.Elem()
for k, v := range extractStructProperties(structValue, 0) {
+ if existing, exists := ret[k]; checkForDuplicateProperties && exists {
+ panic(fmt.Errorf(
+ "%s (%v) is present in properties whereas it should be consolidated into a commonAttributes",
+ k, existing))
+ }
ret[k] = v
}
} else {
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index e904627..f14574c 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -15,10 +15,12 @@
package bp2build
import (
- "android/soong/android"
"fmt"
"strings"
"testing"
+
+ "android/soong/android"
+ "android/soong/python"
)
func TestGenerateSoongModuleTargets(t *testing.T) {
@@ -1215,3 +1217,133 @@
}
}
}
+
+func TestCommonBp2BuildModuleAttrs(t *testing.T) {
+ testCases := []bp2buildTestCase{
+ {
+ description: "Required into data test",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
+ moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ blueprint: `filegroup {
+ name: "reqd",
+}
+
+filegroup {
+ name: "fg_foo",
+ required: ["reqd"],
+ bazel_module: { bp2build_available: true },
+}`,
+ expectedBazelTargets: []string{`filegroup(
+ name = "fg_foo",
+ data = [":reqd"],
+)`,
+ `filegroup(
+ name = "reqd",
+)`,
+ },
+ },
+ {
+ description: "Required via arch into data test",
+ moduleTypeUnderTest: "python_library",
+ moduleTypeUnderTestFactory: python.PythonLibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: python.PythonLibraryBp2Build,
+ blueprint: `python_library {
+ name: "reqdx86",
+ bazel_module: { bp2build_available: false, },
+}
+
+python_library {
+ name: "reqdarm",
+ bazel_module: { bp2build_available: false, },
+}
+
+python_library {
+ name: "fg_foo",
+ arch: {
+ arm: {
+ required: ["reqdarm"],
+ },
+ x86: {
+ required: ["reqdx86"],
+ },
+ },
+ bazel_module: { bp2build_available: true },
+}`,
+ expectedBazelTargets: []string{`py_library(
+ name = "fg_foo",
+ data = select({
+ "//build/bazel/platforms/arch:arm": [":reqdarm"],
+ "//build/bazel/platforms/arch:x86": [":reqdx86"],
+ "//conditions:default": [],
+ }),
+ srcs_version = "PY3",
+)`,
+ },
+ },
+ {
+ description: "Required appended to data test",
+ moduleTypeUnderTest: "python_library",
+ moduleTypeUnderTestFactory: python.PythonLibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: python.PythonLibraryBp2Build,
+ blueprint: `python_library {
+ name: "reqd",
+ srcs: ["src.py"],
+}
+
+python_library {
+ name: "fg_foo",
+ data: ["data.bin"],
+ required: ["reqd"],
+ bazel_module: { bp2build_available: true },
+}`,
+ expectedBazelTargets: []string{
+ `py_library(
+ name = "fg_foo",
+ data = [
+ "data.bin",
+ ":reqd",
+ ],
+ srcs_version = "PY3",
+)`,
+ `py_library(
+ name = "reqd",
+ srcs = ["src.py"],
+ srcs_version = "PY3",
+)`,
+ },
+ filesystem: map[string]string{
+ "data.bin": "",
+ "src.py": "",
+ },
+ },
+ {
+ description: "All props-to-attrs at once together test",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
+ moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ blueprint: `filegroup {
+ name: "reqd"
+}
+filegroup {
+ name: "fg_foo",
+ required: ["reqd"],
+ bazel_module: { bp2build_available: true },
+}`,
+ expectedBazelTargets: []string{
+ `filegroup(
+ name = "fg_foo",
+ data = [":reqd"],
+)`,
+ `filegroup(
+ name = "reqd",
+)`,
+ },
+ filesystem: map[string]string{},
+ },
+ }
+
+ for _, test := range testCases {
+ runBp2BuildTestCaseSimple(t, test)
+ }
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 5952b15..0d65822 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -131,12 +131,13 @@
"//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"],
"//conditions:default": [],
}) + select({
- "//build/bazel/platforms/os:android": ["android.cpp"],
+ "//build/bazel/platforms/os:android": [
+ "android.cpp",
+ "bionic.cpp",
+ ],
"//build/bazel/platforms/os:darwin": ["darwin.cpp"],
"//build/bazel/platforms/os:linux": ["linux.cpp"],
- "//conditions:default": [],
- }) + select({
- "//build/bazel/platforms/os:bionic": ["bionic.cpp"],
+ "//build/bazel/platforms/os:linux_bionic": ["bionic.cpp"],
"//conditions:default": [],
}),
)`}})
@@ -1571,3 +1572,68 @@
)`},
})
}
+
+func TestCcLibraryOsSelects(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library - selects for all os targets",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryPreamble + `
+cc_library_headers { name: "some-headers" }
+cc_library {
+ name: "foo-lib",
+ srcs: ["base.cpp"],
+ target: {
+ android: {
+ srcs: ["android.cpp"],
+ },
+ linux: {
+ srcs: ["linux.cpp"],
+ },
+ linux_glibc: {
+ srcs: ["linux_glibc.cpp"],
+ },
+ darwin: {
+ srcs: ["darwin.cpp"],
+ },
+ bionic: {
+ srcs: ["bionic.cpp"],
+ },
+ linux_musl: {
+ srcs: ["linux_musl.cpp"],
+ },
+ windows: {
+ srcs: ["windows.cpp"],
+ },
+ },
+ include_build_directory: false,
+}
+`,
+ expectedBazelTargets: []string{`cc_library(
+ name = "foo-lib",
+ srcs = ["base.cpp"] + select({
+ "//build/bazel/platforms/os:android": [
+ "android.cpp",
+ "bionic.cpp",
+ "linux.cpp",
+ ],
+ "//build/bazel/platforms/os:darwin": ["darwin.cpp"],
+ "//build/bazel/platforms/os:linux": [
+ "linux.cpp",
+ "linux_glibc.cpp",
+ ],
+ "//build/bazel/platforms/os:linux_bionic": [
+ "bionic.cpp",
+ "linux.cpp",
+ ],
+ "//build/bazel/platforms/os:linux_musl": [
+ "linux.cpp",
+ "linux_musl.cpp",
+ ],
+ "//build/bazel/platforms/os:windows": ["windows.cpp"],
+ "//conditions:default": [],
+ }),
+)`}})
+}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 91b7478..f02ce4d 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1382,7 +1382,8 @@
expectedBazelTargets: []string{`cc_library_static(
name = "target_bionic",
system_dynamic_deps = select({
- "//build/bazel/platforms/os:bionic": [":libc"],
+ "//build/bazel/platforms/os:android": [":libc"],
+ "//build/bazel/platforms/os:linux_bionic": [":libc"],
"//conditions:default": [],
}),
)`},
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index 005f13d..0bcf91d 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -48,6 +48,12 @@
}
}
+ // if there is a select, use the base value as the conditions default value
+ if len(ret) > 0 {
+ ret[bazel.ConditionsDefaultSelectKey] = value
+ value = reflect.Zero(value.Type())
+ }
+
return value, []selects{ret}
}
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 0a86a79..d34a4ba 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -1,12 +1,13 @@
package bp2build
import (
- "android/soong/android"
- "android/soong/cc/config"
"fmt"
"reflect"
"strings"
+ "android/soong/android"
+ "android/soong/cc/config"
+
"github.com/google/blueprint/proptools"
)
diff --git a/bp2build/prebuilt_etc_conversion_test.go b/bp2build/prebuilt_etc_conversion_test.go
index 4e25d1b..62e407b 100644
--- a/bp2build/prebuilt_etc_conversion_test.go
+++ b/bp2build/prebuilt_etc_conversion_test.go
@@ -53,3 +53,40 @@
sub_dir = "tz",
)`}})
}
+
+func TestPrebuiltEtcArchVariant(t *testing.T) {
+ runPrebuiltEtcTestCase(t, bp2buildTestCase{
+ description: "prebuilt_etc - simple example",
+ moduleTypeUnderTest: "prebuilt_etc",
+ moduleTypeUnderTestFactory: etc.PrebuiltEtcFactory,
+ moduleTypeUnderTestBp2BuildMutator: etc.PrebuiltEtcBp2Build,
+ filesystem: map[string]string{},
+ blueprint: `
+prebuilt_etc {
+ name: "apex_tz_version",
+ src: "version/tz_version",
+ filename: "tz_version",
+ sub_dir: "tz",
+ installable: false,
+ arch: {
+ arm: {
+ src: "arm",
+ },
+ arm64: {
+ src: "arm64",
+ },
+ }
+}
+`,
+ expectedBazelTargets: []string{`prebuilt_etc(
+ name = "apex_tz_version",
+ filename = "tz_version",
+ installable = False,
+ src = select({
+ "//build/bazel/platforms/arch:arm": "arm",
+ "//build/bazel/platforms/arch:arm64": "arm64",
+ "//conditions:default": "version/tz_version",
+ }),
+ sub_dir = "tz",
+)`}})
+}
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index 6f6fc11..5b4829e 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -116,3 +116,37 @@
},
})
}
+
+func TestPythonBinaryHostArchVariance(t *testing.T) {
+ runBp2BuildTestCaseSimple(t, bp2buildTestCase{
+ description: "test arch variants",
+ moduleTypeUnderTest: "python_binary_host",
+ moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+ moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
+ filesystem: map[string]string{
+ "dir/arm.py": "",
+ "dir/x86.py": "",
+ },
+ blueprint: `python_binary_host {
+ name: "foo-arm",
+ arch: {
+ arm: {
+ srcs: ["arm.py"],
+ },
+ x86: {
+ srcs: ["x86.py"],
+ },
+ },
+ }`,
+ expectedBazelTargets: []string{
+ `py_binary(
+ name = "foo-arm",
+ srcs = select({
+ "//build/bazel/platforms/arch:arm": ["arm.py"],
+ "//build/bazel/platforms/arch:x86": ["x86.py"],
+ "//conditions:default": [],
+ }),
+)`,
+ },
+ })
+}
diff --git a/bp2build/python_library_conversion_test.go b/bp2build/python_library_conversion_test.go
index b6f45e5..7f983ad 100644
--- a/bp2build/python_library_conversion_test.go
+++ b/bp2build/python_library_conversion_test.go
@@ -154,3 +154,54 @@
},
})
}
+
+func TestPythonLibraryArchVariance(t *testing.T) {
+ testPythonArchVariance(t, "python_library", "py_library",
+ python.PythonLibraryFactory, python.PythonLibraryBp2Build,
+ func(ctx android.RegistrationContext) {})
+}
+
+func TestPythonLibraryHostArchVariance(t *testing.T) {
+ testPythonArchVariance(t, "python_library_host", "py_library",
+ python.PythonLibraryHostFactory, python.PythonLibraryHostBp2Build,
+ func(ctx android.RegistrationContext) {})
+}
+
+// TODO: refactor python_binary_conversion_test to use this
+func testPythonArchVariance(t *testing.T, modType, bazelTarget string,
+ factory android.ModuleFactory, mutator PythonLibBp2Build,
+ registration func(ctx android.RegistrationContext)) {
+ t.Helper()
+ runBp2BuildTestCase(t, registration, bp2buildTestCase{
+ description: fmt.Sprintf("test %s arch variants", modType),
+ moduleTypeUnderTest: modType,
+ moduleTypeUnderTestFactory: factory,
+ moduleTypeUnderTestBp2BuildMutator: mutator,
+ filesystem: map[string]string{
+ "dir/arm.py": "",
+ "dir/x86.py": "",
+ },
+ blueprint: fmt.Sprintf(`%s {
+ name: "foo",
+ arch: {
+ arm: {
+ srcs: ["arm.py"],
+ },
+ x86: {
+ srcs: ["x86.py"],
+ },
+ },
+ }`, modType),
+ expectedBazelTargets: []string{
+ fmt.Sprintf(`%s(
+ name = "foo",
+ srcs = select({
+ "//build/bazel/platforms/arch:arm": ["arm.py"],
+ "//build/bazel/platforms/arch:x86": ["x86.py"],
+ "//conditions:default": [],
+ }),
+ srcs_version = "PY3",
+)`, bazelTarget),
+ },
+ })
+}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 1e7e53c..6c322ee 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -135,17 +135,14 @@
android.FailIfErrored(t, errs)
}
if actualCount, expectedCount := len(bazelTargets), len(tc.expectedBazelTargets); actualCount != expectedCount {
- t.Errorf("%s: Expected %d bazel target, got %d; %v",
- tc.description, expectedCount, actualCount, bazelTargets)
+ t.Errorf("%s: Expected %d bazel target, got `%d``",
+ tc.description, expectedCount, actualCount)
} else {
for i, target := range bazelTargets {
if w, g := tc.expectedBazelTargets[i], target.content; w != g {
t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- tc.description,
- w,
- g,
- )
+ "%s: Expected generated Bazel target to be `%s`, got `%s`",
+ tc.description, w, g)
}
}
}
@@ -312,7 +309,7 @@
Rule_class: "custom",
}
- ctx.CreateBazelTargetModule(m.Name(), props, attrs)
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
}
}
@@ -331,19 +328,19 @@
Rule_class: "my_library",
Bzl_load_location: "//build/bazel/rules:rules.bzl",
}
- ctx.CreateBazelTargetModule(baseName, myLibraryProps, attrs)
+ ctx.CreateBazelTargetModule(myLibraryProps, android.CommonAttributes{Name: baseName}, attrs)
protoLibraryProps := bazel.BazelTargetModuleProperties{
Rule_class: "proto_library",
Bzl_load_location: "//build/bazel/rules:proto.bzl",
}
- ctx.CreateBazelTargetModule(baseName+"_proto_library_deps", protoLibraryProps, attrs)
+ ctx.CreateBazelTargetModule(protoLibraryProps, android.CommonAttributes{Name: baseName + "_proto_library_deps"}, attrs)
myProtoLibraryProps := bazel.BazelTargetModuleProperties{
Rule_class: "my_proto_library",
Bzl_load_location: "//build/bazel/rules:proto.bzl",
}
- ctx.CreateBazelTargetModule(baseName+"_my_proto_library_deps", myProtoLibraryProps, attrs)
+ ctx.CreateBazelTargetModule(myProtoLibraryProps, android.CommonAttributes{Name: baseName + "_my_proto_library_deps"}, attrs)
}
}
diff --git a/cc/androidmk.go b/cc/androidmk.go
index cd52363..93283d0 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -294,9 +294,6 @@
if library.buildStubs() {
entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
}
- if library.apiListCoverageXmlPath.String() != "" {
- entries.SetString("SOONG_CC_API_XML", "$(SOONG_CC_API_XML) "+library.apiListCoverageXmlPath.String())
- }
})
}
// If a library providing a stub is included in an APEX, the private APIs of the library
@@ -394,6 +391,8 @@
if Bool(test.Properties.Test_options.Unit_test) {
entries.SetBool("LOCAL_IS_UNIT_TEST", true)
}
+
+ entries.SetBoolIfTrue("LOCAL_COMPATIBILITY_PER_TESTCASE_DIRECTORY", Bool(test.Properties.Per_testcase_directory))
})
AndroidMkWriteTestData(test.data, entries)
diff --git a/cc/cc.go b/cc/cc.go
index 57e7887..b410834 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -95,6 +95,7 @@
// Used for data dependencies adjacent to tests
DataLibs []string
+ DataBins []string
// Used by DepsMutator to pass system_shared_libs information to check_elf_file.py.
SystemSharedLibs []string
@@ -718,6 +719,7 @@
staticVariantTag = dependencyTag{name: "static variant"}
vndkExtDepTag = dependencyTag{name: "vndk extends"}
dataLibDepTag = dependencyTag{name: "data lib"}
+ dataBinDepTag = dependencyTag{name: "data bin"}
runtimeDepTag = installDependencyTag{name: "runtime lib"}
testPerSrcDepTag = dependencyTag{name: "test_per_src"}
stubImplDepTag = dependencyTag{name: "stub_impl"}
@@ -2274,6 +2276,8 @@
{Mutator: "link", Variation: "shared"},
}, dataLibDepTag, deps.DataLibs...)
+ actx.AddVariationDependencies(nil, dataBinDepTag, deps.DataBins...)
+
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "shared"},
}, runtimeDepTag, deps.RuntimeLibs...)
diff --git a/cc/genrule.go b/cc/genrule.go
index 9df5228..239064f 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -15,6 +15,8 @@
package cc
import (
+ "fmt"
+
"android/soong/android"
"android/soong/genrule"
"android/soong/snapshot"
@@ -36,13 +38,23 @@
// cc_genrule is a genrule that can depend on other cc_* objects.
// The cmd may be run multiple times, once for each of the different arch/etc
-// variations.
+// variations. The following environment variables will be set when the command
+// execute:
+//
+// CC_ARCH the name of the architecture the command is being executed for
+//
+// CC_MULTILIB "lib32" if the architecture the command is being executed for is 32-bit,
+// "lib64" if it is 64-bit.
+//
+// CC_NATIVE_BRIDGE the name of the subdirectory that native bridge libraries are stored in if
+// the architecture has native bridge enabled, empty if it is disabled.
func GenRuleFactory() android.Module {
module := genrule.NewGenRule()
extra := &GenruleExtraProperties{}
module.Extra = extra
module.ImageInterface = extra
+ module.CmdModifier = genruleCmdModifier
module.AddProperties(module.Extra)
android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibBoth)
@@ -53,6 +65,13 @@
return module
}
+func genruleCmdModifier(ctx android.ModuleContext, cmd string) string {
+ target := ctx.Target()
+ arch := target.Arch.ArchType
+ return fmt.Sprintf("CC_ARCH=%s CC_NATIVE_BRIDGE=%s CC_MULTILIB=%s && %s",
+ arch.Name, target.NativeBridgeRelativePath, arch.Multilib, cmd)
+}
+
var _ android.ImageInterface = (*GenruleExtraProperties)(nil)
func (g *GenruleExtraProperties) ImageMutatorBegin(ctx android.BaseModuleContext) {}
diff --git a/cc/genrule_test.go b/cc/genrule_test.go
index b6afb05..f25f704 100644
--- a/cc/genrule_test.go
+++ b/cc/genrule_test.go
@@ -115,3 +115,75 @@
t.Errorf(`want inputs %v, got %v`, expected, got)
}
}
+
+func TestCmdPrefix(t *testing.T) {
+ bp := `
+ cc_genrule {
+ name: "gen",
+ cmd: "echo foo",
+ out: ["out"],
+ native_bridge_supported: true,
+ }
+ `
+
+ testCases := []struct {
+ name string
+ variant string
+ preparer android.FixturePreparer
+
+ arch string
+ nativeBridge string
+ multilib string
+ }{
+ {
+ name: "arm",
+ variant: "android_arm_armv7-a-neon",
+ arch: "arm",
+ multilib: "lib32",
+ },
+ {
+ name: "arm64",
+ variant: "android_arm64_armv8-a",
+ arch: "arm64",
+ multilib: "lib64",
+ },
+ {
+ name: "nativebridge",
+ variant: "android_native_bridge_arm_armv7-a-neon",
+ preparer: android.FixtureModifyConfig(func(config android.Config) {
+ config.Targets[android.Android] = []android.Target{
+ {
+ Os: android.Android,
+ Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}},
+ NativeBridge: android.NativeBridgeDisabled,
+ },
+ {
+ Os: android.Android,
+ Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}},
+ NativeBridge: android.NativeBridgeEnabled,
+ NativeBridgeHostArchName: "x86",
+ NativeBridgeRelativePath: "arm",
+ },
+ }
+ }),
+ arch: "arm",
+ multilib: "lib32",
+ nativeBridge: "arm",
+ },
+ }
+
+ for _, tt := range testCases {
+ t.Run(tt.name, func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ PrepareForIntegrationTestWithCc,
+ android.OptionalFixturePreparer(tt.preparer),
+ ).RunTestWithBp(t, bp)
+ gen := result.ModuleForTests("gen", tt.variant)
+ sboxProto := android.RuleBuilderSboxProtoForTests(t, gen.Output("genrule.sbox.textproto"))
+ cmd := *sboxProto.Commands[0].Command
+ android.AssertStringDoesContain(t, "incorrect CC_ARCH", cmd, "CC_ARCH="+tt.arch+" ")
+ android.AssertStringDoesContain(t, "incorrect CC_NATIVE_BRIDGE", cmd, "CC_NATIVE_BRIDGE="+tt.nativeBridge+" ")
+ android.AssertStringDoesContain(t, "incorrect CC_MULTILIB", cmd, "CC_MULTILIB="+tt.multilib+" ")
+ })
+ }
+}
diff --git a/cc/library.go b/cc/library.go
index de9d01e..77eddbf 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -345,7 +345,7 @@
Bzl_load_location: "//build/bazel/rules:full_cc_library.bzl",
}
- ctx.CreateBazelTargetModule(m.Name(), props, attrs)
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
}
// cc_library creates both static and/or shared libraries for a device and/or
@@ -956,7 +956,7 @@
nativeAbiResult.versionScript)
// Parse symbol file to get API list for coverage
- if library.stubsVersion() == "current" && ctx.PrimaryArch() {
+ if library.stubsVersion() == "current" && ctx.PrimaryArch() && !ctx.inRecovery() && !ctx.inProduct() && !ctx.inVendor() {
library.apiListCoverageXmlPath = parseSymbolFileForAPICoverage(ctx, symbolFile)
}
@@ -1035,6 +1035,8 @@
androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer)
availableFor(string) bool
+
+ getAPIListCoverageXMLPath() android.ModuleOutPath
}
type versionedInterface interface {
@@ -1971,6 +1973,10 @@
mod.ModuleBase.MakeUninstallable()
}
+func (library *libraryDecorator) getAPIListCoverageXMLPath() android.ModuleOutPath {
+ return library.apiListCoverageXmlPath
+}
+
var versioningMacroNamesListKey = android.NewOnceKey("versioningMacroNamesList")
// versioningMacroNamesList returns a singleton map, where keys are "version macro names",
@@ -2434,7 +2440,7 @@
Bzl_load_location: fmt.Sprintf("//build/bazel/rules:%s.bzl", modType),
}
- ctx.CreateBazelTargetModule(module.Name(), props, attrs)
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
}
// TODO(b/199902614): Can this be factored to share with the other Attributes?
diff --git a/cc/library_headers.go b/cc/library_headers.go
index cabeb01..51c1eb8 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -147,5 +147,5 @@
Bzl_load_location: "//build/bazel/rules:cc_library_headers.bzl",
}
- ctx.CreateBazelTargetModule(module.Name(), props, attrs)
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
}
diff --git a/cc/object.go b/cc/object.go
index 4ec2b19..d8bb08f 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -206,7 +206,7 @@
Bzl_load_location: "//build/bazel/rules:cc_object.bzl",
}
- ctx.CreateBazelTargetModule(m.Name(), props, attrs)
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
}
func (object *objectLinker) appendLdflags(flags []string) {
diff --git a/cc/stub_library.go b/cc/stub_library.go
index 1722c80..76da782 100644
--- a/cc/stub_library.go
+++ b/cc/stub_library.go
@@ -15,6 +15,7 @@
package cc
import (
+ "sort"
"strings"
"android/soong/android"
@@ -27,6 +28,8 @@
type stubLibraries struct {
stubLibraryMap map[string]bool
+
+ apiListCoverageXmlPaths []string
}
// Check if the module defines stub, or itself is stub
@@ -53,6 +56,11 @@
s.stubLibraryMap[name] = true
}
}
+ if m.library != nil {
+ if p := m.library.getAPIListCoverageXMLPath().String(); p != "" {
+ s.apiListCoverageXmlPaths = append(s.apiListCoverageXmlPaths, p)
+ }
+ }
}
})
}
@@ -66,4 +74,8 @@
func (s *stubLibraries) MakeVars(ctx android.MakeVarsContext) {
// Convert stub library file names into Makefile variable.
ctx.Strict("STUB_LIBRARIES", strings.Join(android.SortedStringKeys(s.stubLibraryMap), " "))
+
+ // Export the list of API XML files to Make.
+ sort.Strings(s.apiListCoverageXmlPaths)
+ ctx.Strict("SOONG_CC_API_XML", strings.Join(s.apiListCoverageXmlPaths, " "))
}
diff --git a/cc/test.go b/cc/test.go
index 047a69e..c589165 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -80,6 +80,9 @@
// list of shared library modules that should be installed alongside the test
Data_libs []string `android:"arch_variant"`
+ // list of binary modules that should be installed alongside the test
+ Data_bins []string `android:"arch_variant"`
+
// list of compatibility suites (for example "cts", "vts") that the module should be
// installed into.
Test_suites []string `android:"arch_variant"`
@@ -115,6 +118,9 @@
// Add parameterized mainline modules to auto generated test config. The options will be
// handled by TradeFed to download and install the specified modules on the device.
Test_mainline_modules []string
+
+ // Install the test into a folder named for the module in all test suites.
+ Per_testcase_directory *bool
}
func init() {
@@ -347,6 +353,7 @@
deps = test.testDecorator.linkerDeps(ctx, deps)
deps = test.binaryDecorator.linkerDeps(ctx, deps)
deps.DataLibs = append(deps.DataLibs, test.Properties.Data_libs...)
+ deps.DataBins = append(deps.DataBins, test.Properties.Data_bins...)
return deps
}
@@ -386,6 +393,18 @@
RelativeInstallPath: ccModule.installer.relativeInstallPath()})
}
})
+ ctx.VisitDirectDepsWithTag(dataBinDepTag, func(dep android.Module) {
+ depName := ctx.OtherModuleName(dep)
+ ccModule, ok := dep.(*Module)
+ if !ok {
+ ctx.ModuleErrorf("data_bin %q is not a cc module", depName)
+ }
+ if ccModule.OutputFile().Valid() {
+ test.data = append(test.data,
+ android.DataPath{SrcPath: ccModule.OutputFile().Path(),
+ RelativeInstallPath: ccModule.installer.relativeInstallPath()})
+ }
+ })
var configs []tradefed.Config
for _, module := range test.Properties.Test_mainline_modules {
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 85abf59..a1ce8dc 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -673,8 +673,16 @@
func prebuiltEtcBp2BuildInternal(ctx android.TopDownMutatorContext, module *PrebuiltEtc) {
var srcLabelAttribute bazel.LabelAttribute
- if module.properties.Src != nil {
- srcLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *module.properties.Src))
+ for axis, configToProps := range module.GetArchVariantProperties(ctx, &prebuiltEtcProperties{}) {
+ for config, p := range configToProps {
+ props, ok := p.(*prebuiltEtcProperties)
+ if !ok {
+ continue
+ }
+ if props.Src != nil {
+ srcLabelAttribute.SetSelectValue(axis, config, android.BazelLabelForModuleSrcSingle(ctx, *props.Src))
+ }
+ }
}
var filename string
@@ -704,5 +712,5 @@
Bzl_load_location: "//build/bazel/rules:prebuilt_etc.bzl",
}
- ctx.CreateBazelTargetModule(module.Name(), props, attrs)
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index f4bde70..4dd2135 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -156,6 +156,11 @@
// For other packages to make their own genrules with extra
// properties
Extra interface{}
+
+ // CmdModifier can be set by wrappers around genrule to modify the command, for example to
+ // prefix environment variables to it.
+ CmdModifier func(ctx android.ModuleContext, cmd string) string
+
android.ImageInterface
properties generatorProperties
@@ -398,8 +403,13 @@
var outputFiles android.WritablePaths
var zipArgs strings.Builder
+ cmd := String(g.properties.Cmd)
+ if g.CmdModifier != nil {
+ cmd = g.CmdModifier(ctx, cmd)
+ }
+
// Generate tasks, either from genrule or gensrcs.
- for _, task := range g.taskGenerator(ctx, String(g.properties.Cmd), srcFiles) {
+ for _, task := range g.taskGenerator(ctx, cmd, srcFiles) {
if len(task.out) == 0 {
ctx.ModuleErrorf("must have at least one output file")
return
@@ -918,7 +928,7 @@
}
// Create the BazelTargetModule.
- ctx.CreateBazelTargetModule(m.Name(), props, attrs)
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
}
var Bool = proptools.Bool
diff --git a/java/androidmk.go b/java/androidmk.go
index 1914595..537159e 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -71,23 +71,7 @@
entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true})
} else if !library.ApexModuleBase.AvailableFor(android.AvailableToPlatform) {
// Platform variant. If not available for the platform, we don't need Make module.
- // May still need to add some additional dependencies.
- checkedModulePaths := library.additionalCheckedModules
- if len(checkedModulePaths) != 0 {
- entriesList = append(entriesList, android.AndroidMkEntries{
- Class: "FAKE",
- // Need at least one output file in order for this to take effect.
- OutputFile: android.OptionalPathForPath(checkedModulePaths[0]),
- Include: "$(BUILD_PHONY_PACKAGE)",
- ExtraEntries: []android.AndroidMkExtraEntriesFunc{
- func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", checkedModulePaths.Strings()...)
- },
- },
- })
- } else {
- entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true})
- }
+ entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true})
} else {
entriesList = append(entriesList, android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
@@ -123,10 +107,6 @@
requiredUsesLibs, optionalUsesLibs := library.classLoaderContexts.UsesLibs()
entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", append(requiredUsesLibs, optionalUsesLibs...)...)
- if len(library.additionalCheckedModules) != 0 {
- entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...)
- }
-
entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_DICT", library.dexer.proguardDictionary)
entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", library.dexer.proguardUsageZip)
entries.SetString("LOCAL_MODULE_STEM", library.Stem())
@@ -147,20 +127,21 @@
}
// Called for modules that are a component of a test suite.
-func testSuiteComponent(entries *android.AndroidMkEntries, test_suites []string) {
+func testSuiteComponent(entries *android.AndroidMkEntries, test_suites []string, perTestcaseDirectory bool) {
entries.SetString("LOCAL_MODULE_TAGS", "tests")
if len(test_suites) > 0 {
entries.AddCompatibilityTestSuites(test_suites...)
} else {
entries.AddCompatibilityTestSuites("null-suite")
}
+ entries.SetBoolIfTrue("LOCAL_COMPATIBILITY_PER_TESTCASE_DIRECTORY", perTestcaseDirectory)
}
func (j *Test) AndroidMkEntries() []android.AndroidMkEntries {
entriesList := j.Library.AndroidMkEntries()
entries := &entriesList[0]
entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- testSuiteComponent(entries, j.testProperties.Test_suites)
+ testSuiteComponent(entries, j.testProperties.Test_suites, Bool(j.testProperties.Per_testcase_directory))
if j.testConfig != nil {
entries.SetPath("LOCAL_FULL_TEST_CONFIG", j.testConfig)
}
@@ -188,7 +169,7 @@
entriesList := j.Library.AndroidMkEntries()
entries := &entriesList[0]
entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- testSuiteComponent(entries, j.testHelperLibraryProperties.Test_suites)
+ testSuiteComponent(entries, j.testHelperLibraryProperties.Test_suites, Bool(j.testHelperLibraryProperties.Per_testcase_directory))
})
return entriesList
@@ -450,7 +431,7 @@
entriesList := a.AndroidApp.AndroidMkEntries()
entries := &entriesList[0]
entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- testSuiteComponent(entries, a.testProperties.Test_suites)
+ testSuiteComponent(entries, a.testProperties.Test_suites, Bool(a.testProperties.Per_testcase_directory))
if a.testConfig != nil {
entries.SetPath("LOCAL_FULL_TEST_CONFIG", a.testConfig)
}
@@ -466,7 +447,7 @@
entriesList := a.AndroidApp.AndroidMkEntries()
entries := &entriesList[0]
entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- testSuiteComponent(entries, a.appTestHelperAppProperties.Test_suites)
+ testSuiteComponent(entries, a.appTestHelperAppProperties.Test_suites, Bool(a.appTestHelperAppProperties.Per_testcase_directory))
// introduce a flag variable to control the generation of the .config file
entries.SetString("LOCAL_DISABLE_TEST_CONFIG", "true")
})
@@ -677,7 +658,7 @@
entriesList := a.AndroidAppImport.AndroidMkEntries()
entries := &entriesList[0]
entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- testSuiteComponent(entries, a.testProperties.Test_suites)
+ testSuiteComponent(entries, a.testProperties.Test_suites, Bool(a.testProperties.Per_testcase_directory))
androidMkWriteTestData(a.data, entries)
})
return entriesList
diff --git a/java/app.go b/java/app.go
index 2fd6463..6554d66 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1070,6 +1070,9 @@
// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
// explicitly.
Auto_gen_config *bool
+
+ // Install the test into a folder named for the module in all test suites.
+ Per_testcase_directory *bool
}
type AndroidTestHelperApp struct {
@@ -1428,5 +1431,5 @@
Bzl_load_location: "//build/bazel/rules:android_app_certificate.bzl",
}
- ctx.CreateBazelTargetModule(module.Name(), props, attrs)
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
}
diff --git a/java/base.go b/java/base.go
index 579085b..ca34f2e 100644
--- a/java/base.go
+++ b/java/base.go
@@ -433,9 +433,6 @@
// expanded Jarjar_rules
expandJarjarRules android.Path
- // list of additional targets for checkbuild
- additionalCheckedModules android.Paths
-
// Extra files generated by the module type to be added as java resources.
extraResources android.Paths
@@ -1265,10 +1262,25 @@
// Check package restrictions if necessary.
if len(j.properties.Permitted_packages) > 0 {
- // Check packages and copy to package-checked file.
+ // Time stamp file created by the package check rule.
pkgckFile := android.PathForModuleOut(ctx, "package-check.stamp")
+
+ // Create a rule to copy the output jar to another path and add a validate dependency that
+ // will check that the jar only contains the permitted packages. The new location will become
+ // the output file of this module.
+ inputFile := outputFile
+ outputFile = android.PathForModuleOut(ctx, "package-check", jarName).OutputPath
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: inputFile,
+ Output: outputFile,
+ // Make sure that any dependency on the output file will cause ninja to run the package check
+ // rule.
+ Validation: pkgckFile,
+ })
+
+ // Check packages and create a timestamp file when complete.
CheckJarPackages(ctx, pkgckFile, outputFile, j.properties.Permitted_packages)
- j.additionalCheckedModules = append(j.additionalCheckedModules, pkgckFile)
if ctx.Failed() {
return
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 79c73ca..8f18790 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -139,6 +139,74 @@
BootclasspathFragmentsDepsProperties
}
+type SourceOnlyBootclasspathProperties struct {
+ Hidden_api struct {
+ // Contains prefixes of a package hierarchy that is provided solely by this
+ // bootclasspath_fragment.
+ //
+ // This affects the signature patterns file that is used to select the subset of monolithic
+ // hidden API flags. See split_packages property for more details.
+ Package_prefixes []string
+
+ // The list of split packages provided by this bootclasspath_fragment.
+ //
+ // A split package is one that contains classes which are provided by multiple
+ // bootclasspath_fragment modules.
+ //
+ // This defaults to "*" - which treats all packages as being split. A module that has no split
+ // packages must specify an empty list.
+ //
+ // This affects the signature patterns file that is generated by a bootclasspath_fragment and
+ // used to select the subset of monolithic hidden API flags against which the flags generated
+ // by the bootclasspath_fragment are compared.
+ //
+ // The signature patterns file selects the subset of monolithic hidden API flags using a number
+ // of patterns, i.e.:
+ // * The qualified name (including package) of an outermost class, e.g. java/lang/Character.
+ // This selects all the flags for all the members of this class and any nested classes.
+ // * A package wildcard, e.g. java/lang/*. This selects all the flags for all the members of all
+ // the classes in this package (but not in sub-packages).
+ // * A recursive package wildcard, e.g. java/**. This selects all the flags for all the members
+ // of all the classes in this package and sub-packages.
+ //
+ // The signature patterns file is constructed as follows:
+ // * All the signatures are retrieved from the all-flags.csv file.
+ // * The member and inner class names are removed.
+ // * If a class is in a split package then that is kept, otherwise the class part is removed
+ // and replaced with a wildcard, i.e. *.
+ // * If a package matches a package prefix then the package is removed.
+ // * All the package prefixes are added with a recursive wildcard appended to each, i.e. **.
+ // * The resulting patterns are sorted.
+ //
+ // So, by default (i.e. without specifying any package_prefixes or split_packages) the signature
+ // patterns is a list of class names, because there are no package packages and all packages are
+ // assumed to be split.
+ //
+ // If any split packages are specified then only those packages are treated as split and all
+ // other packages are treated as belonging solely to the bootclasspath_fragment and so they use
+ // wildcard package patterns.
+ //
+ // So, if an empty list of split packages is specified then the signature patterns file just
+ // includes a wildcard package pattern for every package provided by the bootclasspath_fragment.
+ //
+ // If split_packages are specified and a package that is split is not listed then it could lead
+ // to build failures as it will select monolithic flags that are generated by another
+ // bootclasspath_fragment to compare against the flags provided by this fragment. The latter
+ // will obviously not contain those flags and that can cause the comparison and build to fail.
+ //
+ // If any package prefixes are specified then any matching packages are removed from the
+ // signature patterns and replaced with a single recursive package pattern.
+ //
+ // It is not strictly necessary to specify either package_prefixes or split_packages as the
+ // defaults will produce a valid set of signature patterns. However, those patterns may include
+ // implementation details, e.g. names of implementation classes or packages, which will be
+ // exported to the sdk snapshot in the signature patterns file. That is something that should be
+ // avoided where possible. Specifying package_prefixes and split_packages allows those
+ // implementation details to be excluded from the snapshot.
+ Split_packages []string
+ }
+}
+
type BootclasspathFragmentModule struct {
android.ModuleBase
android.ApexModuleBase
@@ -147,6 +215,8 @@
properties bootclasspathFragmentProperties
+ sourceOnlyProperties SourceOnlyBootclasspathProperties
+
// Collect the module directory for IDE info in java/jdeps.go.
modulePaths []string
}
@@ -180,7 +250,7 @@
func bootclasspathFragmentFactory() android.Module {
m := &BootclasspathFragmentModule{}
- m.AddProperties(&m.properties)
+ m.AddProperties(&m.properties, &m.sourceOnlyProperties)
android.InitApexModule(m)
android.InitSdkAwareModule(m)
initClasspathFragment(m, BOOTCLASSPATH)
@@ -590,7 +660,7 @@
// TODO(b/192868581): Remove once the source and prebuilts provide a signature patterns file of
// their own.
if output.SignaturePatternsPath == nil {
- output.SignaturePatternsPath = buildRuleSignaturePatternsFile(ctx, output.AllFlagsPath)
+ output.SignaturePatternsPath = buildRuleSignaturePatternsFile(ctx, output.AllFlagsPath, []string{"*"}, nil)
}
// Initialize a HiddenAPIInfo structure.
@@ -659,7 +729,20 @@
func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
// Generate the rules to create the hidden API flags and update the supplied hiddenAPIInfo with the
// paths to the created files.
- return hiddenAPIRulesForBootclasspathFragment(ctx, contents, input)
+ output := hiddenAPIRulesForBootclasspathFragment(ctx, contents, input)
+
+ // If the module specifies split_packages or package_prefixes then use those to generate the
+ // signature patterns.
+ splitPackages := b.sourceOnlyProperties.Hidden_api.Split_packages
+ packagePrefixes := b.sourceOnlyProperties.Hidden_api.Package_prefixes
+ if splitPackages != nil || packagePrefixes != nil {
+ if splitPackages == nil {
+ splitPackages = []string{"*"}
+ }
+ output.SignaturePatternsPath = buildRuleSignaturePatternsFile(ctx, output.AllFlagsPath, splitPackages, packagePrefixes)
+ }
+
+ return output
}
// produceBootImageFiles builds the boot image files from the source if it is required.
@@ -767,14 +850,20 @@
// The path to the generated index.csv file.
Index_path android.OptionalPath
- // The path to the generated signature-patterns.csv file.
- Signature_patterns_path android.OptionalPath
-
// The path to the generated stub-flags.csv file.
- Stub_flags_path android.OptionalPath
+ Stub_flags_path android.OptionalPath `supported_build_releases:"S"`
// The path to the generated all-flags.csv file.
- All_flags_path android.OptionalPath
+ All_flags_path android.OptionalPath `supported_build_releases:"S"`
+
+ // The path to the generated signature-patterns.csv file.
+ Signature_patterns_path android.OptionalPath `supported_build_releases:"T+"`
+
+ // The path to the generated filtered-stub-flags.csv file.
+ Filtered_stub_flags_path android.OptionalPath `supported_build_releases:"T+"`
+
+ // The path to the generated filtered-flags.csv file.
+ Filtered_flags_path android.OptionalPath `supported_build_releases:"T+"`
}
func (b *bootclasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
@@ -793,10 +882,13 @@
b.Metadata_path = android.OptionalPathForPath(hiddenAPIInfo.MetadataPath)
b.Index_path = android.OptionalPathForPath(hiddenAPIInfo.IndexPath)
- b.Signature_patterns_path = android.OptionalPathForPath(hiddenAPIInfo.SignaturePatternsPath)
b.Stub_flags_path = android.OptionalPathForPath(hiddenAPIInfo.StubFlagsPath)
b.All_flags_path = android.OptionalPathForPath(hiddenAPIInfo.AllFlagsPath)
+ b.Signature_patterns_path = android.OptionalPathForPath(hiddenAPIInfo.SignaturePatternsPath)
+ b.Filtered_stub_flags_path = android.OptionalPathForPath(hiddenAPIInfo.FilteredStubFlagsPath)
+ b.Filtered_flags_path = android.OptionalPathForPath(hiddenAPIInfo.FilteredFlagsPath)
+
// Copy stub_libs properties.
b.Stub_libs = module.properties.Api.Stub_libs
b.Core_platform_stub_libs = module.properties.Core_platform_api.Stub_libs
@@ -861,9 +953,13 @@
copyOptionalPath(b.Annotation_flags_path, "annotation_flags")
copyOptionalPath(b.Metadata_path, "metadata")
copyOptionalPath(b.Index_path, "index")
- copyOptionalPath(b.Signature_patterns_path, "signature_patterns")
+
copyOptionalPath(b.Stub_flags_path, "stub_flags")
copyOptionalPath(b.All_flags_path, "all_flags")
+
+ copyOptionalPath(b.Signature_patterns_path, "signature_patterns")
+ copyOptionalPath(b.Filtered_stub_flags_path, "filtered_stub_flags")
+ copyOptionalPath(b.Filtered_flags_path, "filtered_flags")
}
var _ android.SdkMemberType = (*bootclasspathFragmentMemberType)(nil)
@@ -889,6 +985,12 @@
// The path to the all-flags.csv file created by the bootclasspath_fragment.
All_flags *string `android:"path"`
+
+ // The path to the filtered-stub-flags.csv file created by the bootclasspath_fragment.
+ Filtered_stub_flags *string `android:"path"`
+
+ // The path to the filtered-flags.csv file created by the bootclasspath_fragment.
+ Filtered_flags *string `android:"path"`
}
}
@@ -915,9 +1017,9 @@
// produceHiddenAPIOutput returns a path to the prebuilt all-flags.csv or nil if none is specified.
func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
- pathForOptionalSrc := func(src *string) android.Path {
+ pathForOptionalSrc := func(src *string, defaultPath android.Path) android.Path {
if src == nil {
- return nil
+ return defaultPath
}
return android.PathForModuleSrc(ctx, *src)
}
@@ -938,13 +1040,19 @@
AnnotationFlagsPath: pathForSrc("hidden_api.annotation_flags", module.prebuiltProperties.Hidden_api.Annotation_flags),
MetadataPath: pathForSrc("hidden_api.metadata", module.prebuiltProperties.Hidden_api.Metadata),
IndexPath: pathForSrc("hidden_api.index", module.prebuiltProperties.Hidden_api.Index),
- SignaturePatternsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Signature_patterns),
- StubFlagsPath: pathForSrc("hidden_api.stub_flags", module.prebuiltProperties.Hidden_api.Stub_flags),
- AllFlagsPath: pathForSrc("hidden_api.all_flags", module.prebuiltProperties.Hidden_api.All_flags),
+ SignaturePatternsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Signature_patterns, nil),
+ // TODO: Temporarily handle stub_flags/all_flags properties until prebuilts have been updated.
+ StubFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Stub_flags, nil),
+ AllFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.All_flags, nil),
},
+
EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
}
+ // TODO: Temporarily fallback to stub_flags/all_flags properties until prebuilts have been updated.
+ output.FilteredStubFlagsPath = pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Filtered_stub_flags, output.StubFlagsPath)
+ output.FilteredFlagsPath = pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Filtered_flags, output.AllFlagsPath)
+
return &output
}
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index b9a1ca7..0cc960d 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -548,18 +548,18 @@
}
}
-// StubFlagSubset returns a SignatureCsvSubset that contains a path to a stub-flags.csv file and a
-// path to a signature-patterns.csv file that defines a subset of the monolithic stub flags file,
-// i.e. out/soong/hiddenapi/hiddenapi-stub-flags.txt, against which it will be compared.
+// StubFlagSubset returns a SignatureCsvSubset that contains a path to a filtered-stub-flags.csv
+// file and a path to a signature-patterns.csv file that defines a subset of the monolithic stub
+// flags file, i.e. out/soong/hiddenapi/hiddenapi-stub-flags.txt, against which it will be compared.
func (i *HiddenAPIInfo) StubFlagSubset() SignatureCsvSubset {
- return SignatureCsvSubset{i.StubFlagsPath, i.SignaturePatternsPath}
+ return SignatureCsvSubset{i.FilteredStubFlagsPath, i.SignaturePatternsPath}
}
-// FlagSubset returns a SignatureCsvSubset that contains a path to an all-flags.csv file and a
+// FlagSubset returns a SignatureCsvSubset that contains a path to a filtered-flags.csv file and a
// path to a signature-patterns.csv file that defines a subset of the monolithic flags file, i.e.
// out/soong/hiddenapi/hiddenapi-flags.csv, against which it will be compared.
func (i *HiddenAPIInfo) FlagSubset() SignatureCsvSubset {
- return SignatureCsvSubset{i.AllFlagsPath, i.SignaturePatternsPath}
+ return SignatureCsvSubset{i.FilteredFlagsPath, i.SignaturePatternsPath}
}
var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
@@ -784,9 +784,6 @@
// HiddenAPIFlagOutput contains paths to output files from the hidden API flag generation for a
// bootclasspath_fragment module.
type HiddenAPIFlagOutput struct {
- // The path to the generated stub-flags.csv file.
- StubFlagsPath android.Path
-
// The path to the generated annotation-flags.csv file.
AnnotationFlagsPath android.Path
@@ -796,12 +793,21 @@
// The path to the generated index.csv file.
IndexPath android.Path
+ // The path to the generated stub-flags.csv file.
+ StubFlagsPath android.Path
+
// The path to the generated all-flags.csv file.
AllFlagsPath android.Path
// The path to the generated signature-patterns.txt file which defines the subset of the
// monolithic hidden API files provided in this.
SignaturePatternsPath android.Path
+
+ // The path to the generated filtered-stub-flags.csv file.
+ FilteredStubFlagsPath android.Path
+
+ // The path to the generated filtered-flags.csv file.
+ FilteredFlagsPath android.Path
}
// bootDexJarByModule is a map from base module name (without prebuilt_ prefix) to the boot dex
@@ -937,13 +943,22 @@
// buildRuleSignaturePatternsFile creates a rule to generate a file containing the set of signature
// patterns that will select a subset of the monolithic flags.
-func buildRuleSignaturePatternsFile(ctx android.ModuleContext, flagsPath android.Path) android.Path {
+func buildRuleSignaturePatternsFile(ctx android.ModuleContext, flagsPath android.Path, splitPackages []string, packagePrefixes []string) android.Path {
patternsFile := android.PathForModuleOut(ctx, "modular-hiddenapi", "signature-patterns.csv")
// Create a rule to validate the output from the following rule.
rule := android.NewRuleBuilder(pctx, ctx)
+
+ // Quote any * in the packages to avoid them being expanded by the shell.
+ quotedSplitPackages := []string{}
+ for _, pkg := range splitPackages {
+ quotedSplitPackages = append(quotedSplitPackages, strings.ReplaceAll(pkg, "*", "\\*"))
+ }
+
rule.Command().
BuiltTool("signature_patterns").
FlagWithInput("--flags ", flagsPath).
+ FlagForEachArg("--split-package ", quotedSplitPackages).
+ FlagForEachArg("--package-prefix ", packagePrefixes).
FlagWithOutput("--output ", patternsFile)
rule.Build("hiddenAPISignaturePatterns", "hidden API signature patterns")
@@ -1067,11 +1082,13 @@
// Store the paths in the info for use by other modules and sdk snapshot generation.
output := HiddenAPIOutput{
HiddenAPIFlagOutput: HiddenAPIFlagOutput{
- StubFlagsPath: filteredStubFlagsCSV,
- AnnotationFlagsPath: annotationFlagsCSV,
- MetadataPath: metadataCSV,
- IndexPath: indexCSV,
- AllFlagsPath: filteredFlagsCSV,
+ AnnotationFlagsPath: annotationFlagsCSV,
+ MetadataPath: metadataCSV,
+ IndexPath: indexCSV,
+ StubFlagsPath: stubFlagsCSV,
+ AllFlagsPath: allFlagsCSV,
+ FilteredStubFlagsPath: filteredStubFlagsCSV,
+ FilteredFlagsPath: filteredFlagsCSV,
},
EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
}
diff --git a/java/java.go b/java/java.go
index 23809df..287bcfa 100644
--- a/java/java.go
+++ b/java/java.go
@@ -781,6 +781,9 @@
// Names of modules containing JNI libraries that should be installed alongside the test.
Jni_libs []string
+
+ // Install the test into a folder named for the module in all test suites.
+ Per_testcase_directory *bool
}
type hostTestProperties struct {
@@ -792,6 +795,9 @@
// list of compatibility suites (for example "cts", "vts") that the module should be
// installed into.
Test_suites []string `android:"arch_variant"`
+
+ // Install the test into a folder named for the module in all test suites.
+ Per_testcase_directory *bool
}
type prebuiltTestProperties struct {
@@ -1392,10 +1398,19 @@
if dexOutputPath := di.PrebuiltExportPath(apexRootRelativePathToJavaLib(j.BaseModuleName())); dexOutputPath != nil {
dexJarFile := makeDexJarPathFromPath(dexOutputPath)
j.dexJarFile = dexJarFile
- j.dexJarInstallFile = android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, apexRootRelativePathToJavaLib(j.BaseModuleName()))
+ installPath := android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, apexRootRelativePathToJavaLib(j.BaseModuleName()))
+ j.dexJarInstallFile = installPath
// Initialize the hiddenapi structure.
j.initHiddenAPI(ctx, dexJarFile, outputFile, nil)
+
+ j.dexpreopter.installPath = j.dexpreopter.getInstallPath(ctx, installPath)
+ if j.dexProperties.Uncompress_dex == nil {
+ // If the value was not force-set by the user, use reasonable default based on the module.
+ j.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter))
+ }
+ j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
+ j.dexpreopt(ctx, dexOutputPath)
} else {
// This should never happen as a variant for a prebuilt_apex is only created if the
// prebuilt_apex has been configured to export the java library dex file.
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index 1b4fda8..f209f4a 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -123,7 +123,7 @@
// For non test apexes, make sure that all contents are actually declared in make.
if global.ApexSystemServerJars.Len() > 0 && len(unknown) > 0 && !android.IsModuleInVersionedSdk(ctx.Module()) {
- ctx.ModuleErrorf("%s in contents must also be declared in PRODUCT_UPDATABLE_SYSTEM_SERVER_JARS", unknown)
+ ctx.ModuleErrorf("%s in contents must also be declared in PRODUCT_APEX_SYSTEM_SERVER_JARS", unknown)
}
return jars
diff --git a/mk2rbc/cmd/mk2rbc.go b/mk2rbc/cmd/mk2rbc.go
index 7b5f298..d8e7018 100644
--- a/mk2rbc/cmd/mk2rbc.go
+++ b/mk2rbc/cmd/mk2rbc.go
@@ -154,47 +154,39 @@
}
// Convert!
- ok := true
- if *launcher != "" {
- if len(flag.Args()) != 1 {
- quit(fmt.Errorf("a launcher can be generated only for a single product"))
- }
- product := flag.Args()[0]
+ files := flag.Args()
+ if *allInSource {
productConfigMap := buildProductConfigMap()
- path, found := productConfigMap[product]
- if !found {
- quit(fmt.Errorf("cannot generate configuration launcher for %s, it is not a known product",
- product))
+ for _, path := range productConfigMap {
+ files = append(files, path)
+ }
+ }
+ ok := true
+ for _, mkFile := range files {
+ ok = convertOne(mkFile) && ok
+ }
+
+ if *launcher != "" {
+ if len(files) != 1 {
+ quit(fmt.Errorf("a launcher can be generated only for a single product"))
}
versionDefaults, err := generateVersionDefaults()
if err != nil {
quit(err)
}
- ok = convertOne(path) && ok
versionDefaultsPath := outputFilePath(versionDefaultsMk)
err = writeGenerated(versionDefaultsPath, versionDefaults)
if err != nil {
- fmt.Fprintf(os.Stderr, "%s:%s", path, err)
+ fmt.Fprintf(os.Stderr, "%s:%s", files[0], err)
ok = false
}
- err = writeGenerated(*launcher, mk2rbc.Launcher(outputFilePath(path), versionDefaultsPath,
- mk2rbc.MakePath2ModuleName(path)))
+ err = writeGenerated(*launcher, mk2rbc.Launcher(outputFilePath(files[0]), versionDefaultsPath,
+ mk2rbc.MakePath2ModuleName(files[0])))
if err != nil {
- fmt.Fprintf(os.Stderr, "%s:%s", path, err)
+ fmt.Fprintf(os.Stderr, "%s:%s", files[0], err)
ok = false
}
- } else {
- files := flag.Args()
- if *allInSource {
- productConfigMap := buildProductConfigMap()
- for _, path := range productConfigMap {
- files = append(files, path)
- }
- }
- for _, mkFile := range files {
- ok = convertOne(mkFile) && ok
- }
}
printStats()
diff --git a/python/binary.go b/python/binary.go
index bc2768c..bf6167c 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -37,7 +37,6 @@
type bazelPythonBinaryAttributes struct {
Main string
Srcs bazel.LabelListAttribute
- Data bazel.LabelListAttribute
Deps bazel.LabelListAttribute
Python_version string
}
@@ -63,6 +62,7 @@
}
}
}
+
// TODO(b/182306917): this doesn't fully handle all nested props versioned
// by the python version, which would have been handled by the version split
// mutator. This is sufficient for very simple python_binary_host modules
@@ -80,15 +80,11 @@
// do nothing, since python_version defaults to PY3.
}
- srcs := android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
- data := android.BazelLabelForModuleSrc(ctx, m.properties.Data)
- deps := android.BazelLabelForModuleDeps(ctx, m.properties.Libs)
-
+ baseAttrs := m.makeArchVariantBaseAttributes(ctx)
attrs := &bazelPythonBinaryAttributes{
Main: main,
- Srcs: bazel.MakeLabelListAttribute(srcs),
- Data: bazel.MakeLabelListAttribute(data),
- Deps: bazel.MakeLabelListAttribute(deps),
+ Srcs: baseAttrs.Srcs,
+ Deps: baseAttrs.Deps,
Python_version: python_version,
}
@@ -97,7 +93,10 @@
Rule_class: "py_binary",
}
- ctx.CreateBazelTargetModule(m.Name(), props, attrs)
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{
+ Name: m.Name(),
+ Data: baseAttrs.Data,
+ }, attrs)
}
type BinaryProperties struct {
diff --git a/python/library.go b/python/library.go
index a132216..d136a4e 100644
--- a/python/library.go
+++ b/python/library.go
@@ -45,7 +45,6 @@
type bazelPythonLibraryAttributes struct {
Srcs bazel.LabelListAttribute
- Data bazel.LabelListAttribute
Deps bazel.LabelListAttribute
Srcs_version string
}
@@ -88,14 +87,10 @@
// do nothing, since python_version defaults to PY2ANDPY3
}
- srcs := android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
- data := android.BazelLabelForModuleSrc(ctx, m.properties.Data)
- deps := android.BazelLabelForModuleDeps(ctx, m.properties.Libs)
-
+ baseAttrs := m.makeArchVariantBaseAttributes(ctx)
attrs := &bazelPythonLibraryAttributes{
- Srcs: bazel.MakeLabelListAttribute(srcs),
- Data: bazel.MakeLabelListAttribute(data),
- Deps: bazel.MakeLabelListAttribute(deps),
+ Srcs: baseAttrs.Srcs,
+ Deps: baseAttrs.Deps,
Srcs_version: python_version,
}
@@ -104,7 +99,10 @@
Rule_class: "py_library",
}
- ctx.CreateBazelTargetModule(m.Name(), props, attrs)
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{
+ Name: m.Name(),
+ Data: baseAttrs.Data,
+ }, attrs)
}
func PythonLibraryFactory() android.Module {
diff --git a/python/python.go b/python/python.go
index f900172..401d91f 100644
--- a/python/python.go
+++ b/python/python.go
@@ -22,6 +22,7 @@
"regexp"
"strings"
+ "android/soong/bazel"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -120,6 +121,18 @@
Embedded_launcher *bool `blueprint:"mutated"`
}
+type baseAttributes struct {
+ // TODO(b/200311466): Probably not translate b/c Bazel has no good equiv
+ //Pkg_path bazel.StringAttribute
+ // TODO: Related to Pkg_bath and similarLy gated
+ //Is_internal bazel.BoolAttribute
+ // Combines Srcs and Exclude_srcs
+ Srcs bazel.LabelListAttribute
+ Deps bazel.LabelListAttribute
+ // Combines Data and Java_data (invariant)
+ Data bazel.LabelListAttribute
+}
+
// Used to store files of current module after expanding dependencies
type pathMapping struct {
dest string
@@ -177,6 +190,25 @@
}
}
+func (m *Module) makeArchVariantBaseAttributes(ctx android.TopDownMutatorContext) baseAttributes {
+ var attrs baseAttributes
+ archVariantBaseProps := m.GetArchVariantProperties(ctx, &BaseProperties{})
+ for axis, configToProps := range archVariantBaseProps {
+ for config, props := range configToProps {
+ if baseProps, ok := props.(*BaseProperties); ok {
+ attrs.Srcs.SetSelectValue(axis, config,
+ android.BazelLabelForModuleSrcExcludes(ctx, baseProps.Srcs, baseProps.Exclude_srcs))
+ attrs.Deps.SetSelectValue(axis, config,
+ android.BazelLabelForModuleDeps(ctx, baseProps.Libs))
+ data := android.BazelLabelForModuleSrc(ctx, baseProps.Data)
+ data.Append(android.BazelLabelForModuleSrc(ctx, baseProps.Java_data))
+ attrs.Data.SetSelectValue(axis, config, data)
+ }
+ }
+ }
+ return attrs
+}
+
// bootstrapper interface should be implemented for runnable modules, e.g. binary and test
type bootstrapper interface {
bootstrapperProps() []interface{}
diff --git a/rust/rust.go b/rust/rust.go
index 0a7d68d..b9afc7f 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -663,7 +663,7 @@
}
func (mod *Module) installable(apexInfo android.ApexInfo) bool {
- if !mod.EverInstallable() {
+ if !proptools.BoolDefault(mod.Installable(), mod.EverInstallable()) {
return false
}
diff --git a/scripts/check_boot_jars/package_allowed_list.txt b/scripts/check_boot_jars/package_allowed_list.txt
index 9aae2a9..b1b1e7e 100644
--- a/scripts/check_boot_jars/package_allowed_list.txt
+++ b/scripts/check_boot_jars/package_allowed_list.txt
@@ -71,6 +71,7 @@
javax\.xml\.xpath
jdk\.internal\.math
jdk\.internal\.misc
+jdk\.internal\.reflect
jdk\.internal\.util
jdk\.internal\.vm\.annotation
jdk\.net
diff --git a/scripts/hiddenapi/signature_patterns.py b/scripts/hiddenapi/signature_patterns.py
index 0acb2a0..e75ee95 100755
--- a/scripts/hiddenapi/signature_patterns.py
+++ b/scripts/hiddenapi/signature_patterns.py
@@ -13,8 +13,10 @@
# 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.
-"""Generate a set of signature patterns from the modular flags generated by a
-bootclasspath_fragment that can be used to select a subset of monolithic flags
+"""Generate a set of signature patterns for a bootclasspath_fragment.
+
+The patterns are generated from the modular flags produced by the
+bootclasspath_fragment and are used to select a subset of the monolithic flags
against which the modular flags can be compared.
"""
@@ -22,33 +24,122 @@
import csv
import sys
+
def dict_reader(csvfile):
return csv.DictReader(
- csvfile, delimiter=',', quotechar='|', fieldnames=['signature']
- )
+ csvfile, delimiter=',', quotechar='|', fieldnames=['signature'])
-def produce_patterns_from_file(file):
+def dotPackageToSlashPackage(pkg):
+ return pkg.replace('.', '/')
+
+
+def slashPackageToDotPackage(pkg):
+ return pkg.replace('/', '.')
+
+
+def isSplitPackage(splitPackages, pkg):
+ return splitPackages and (pkg in splitPackages or '*' in splitPackages)
+
+
+def matchedByPackagePrefixPattern(packagePrefixes, prefix):
+ for packagePrefix in packagePrefixes:
+ if prefix == packagePrefix:
+ return packagePrefix
+ elif prefix.startswith(packagePrefix) and prefix[len(
+ packagePrefix)] == '/':
+ return packagePrefix
+ return False
+
+
+def validate_package_prefixes(splitPackages, packagePrefixes):
+ # If there are no package prefixes then there is no possible conflict
+ # between them and the split packages.
+ if len(packagePrefixes) == 0:
+ return
+
+ # Check to make sure that the split packages and package prefixes do not
+ # overlap.
+ errors = []
+ for splitPackage in splitPackages:
+ if splitPackage == '*':
+ # A package prefix matches a split package.
+ packagePrefixesForOutput = ', '.join(
+ map(slashPackageToDotPackage, packagePrefixes))
+ errors.append(
+ 'split package "*" conflicts with all package prefixes %s\n'
+ ' add split_packages:[] to fix' % packagePrefixesForOutput)
+ else:
+ packagePrefix = matchedByPackagePrefixPattern(
+ packagePrefixes, splitPackage)
+ if packagePrefix:
+ # A package prefix matches a split package.
+ splitPackageForOutput = slashPackageToDotPackage(splitPackage)
+ packagePrefixForOutput = slashPackageToDotPackage(packagePrefix)
+ errors.append(
+ 'split package %s is matched by package prefix %s' %
+ (splitPackageForOutput, packagePrefixForOutput))
+ return errors
+
+
+def validate_split_packages(splitPackages):
+ errors = []
+ if '*' in splitPackages and len(splitPackages) > 1:
+ errors.append('split packages are invalid as they contain both the'
+ ' wildcard (*) and specific packages, use the wildcard or'
+ ' specific packages, not a mixture')
+ return errors
+
+
+def produce_patterns_from_file(file, splitPackages=None, packagePrefixes=None):
with open(file, 'r') as f:
- return produce_patterns_from_stream(f)
+ return produce_patterns_from_stream(f, splitPackages, packagePrefixes)
-def produce_patterns_from_stream(stream):
- # Read in all the signatures into a list and remove member names.
+def produce_patterns_from_stream(stream,
+ splitPackages=None,
+ packagePrefixes=None):
+ splitPackages = set(splitPackages or [])
+ packagePrefixes = list(packagePrefixes or [])
+ # Read in all the signatures into a list and remove any unnecessary class
+ # and member names.
patterns = set()
for row in dict_reader(stream):
signature = row['signature']
- text = signature.removeprefix("L")
+ text = signature.removeprefix('L')
# Remove the class specific member signature
- pieces = text.split(";->")
+ pieces = text.split(';->')
qualifiedClassName = pieces[0]
- # Remove inner class names as they cannot be separated
- # from the containing outer class.
- pieces = qualifiedClassName.split("$", maxsplit=1)
- pattern = pieces[0]
+ pieces = qualifiedClassName.rsplit('/', maxsplit=1)
+ pkg = pieces[0]
+ # If the package is split across multiple modules then it cannot be used
+ # to select the subset of the monolithic flags that this module
+ # produces. In that case we need to keep the name of the class but can
+ # discard any nested class names as an outer class cannot be split
+ # across modules.
+ #
+ # If the package is not split then every class in the package must be
+ # provided by this module so there is no need to list the classes
+ # explicitly so just use the package name instead.
+ if isSplitPackage(splitPackages, pkg):
+ # Remove inner class names.
+ pieces = qualifiedClassName.split('$', maxsplit=1)
+ pattern = pieces[0]
+ else:
+ # Add a * to ensure that the pattern matches the classes in that
+ # package.
+ pattern = pkg + '/*'
patterns.add(pattern)
- patterns = list(patterns) #pylint: disable=redefined-variable-type
+ # Remove any patterns that would be matched by a package prefix pattern.
+ patterns = list(
+ filter(lambda p: not matchedByPackagePrefixPattern(packagePrefixes, p),
+ patterns))
+ # Add the package prefix patterns to the list. Add a ** to ensure that each
+ # package prefix pattern will match the classes in that package and all
+ # sub-packages.
+ patterns = patterns + list(map(lambda x: x + '/**', packagePrefixes))
+ # Sort the patterns.
patterns.sort()
return patterns
@@ -56,24 +147,47 @@
def main(args):
args_parser = argparse.ArgumentParser(
description='Generate a set of signature patterns '
- 'that select a subset of monolithic hidden API files.'
- )
+ 'that select a subset of monolithic hidden API files.')
args_parser.add_argument(
'--flags',
help='The stub flags file which contains an entry for every dex member',
)
+ args_parser.add_argument(
+ '--split-package',
+ action='append',
+ help='A package that is split across multiple bootclasspath_fragment modules'
+ )
+ args_parser.add_argument(
+ '--package-prefix',
+ action='append',
+ help='A package prefix unique to this set of flags')
args_parser.add_argument('--output', help='Generated signature prefixes')
args = args_parser.parse_args(args)
+ splitPackages = set(map(dotPackageToSlashPackage, args.split_package or []))
+ errors = validate_split_packages(splitPackages)
+
+ packagePrefixes = list(
+ map(dotPackageToSlashPackage, args.package_prefix or []))
+
+ if not errors:
+ errors = validate_package_prefixes(splitPackages, packagePrefixes)
+
+ if errors:
+ for error in errors:
+ print(error)
+ sys.exit(1)
+
# Read in all the patterns into a list.
- patterns = produce_patterns_from_file(args.flags)
+ patterns = produce_patterns_from_file(args.flags, splitPackages,
+ packagePrefixes)
# Write out all the patterns.
with open(args.output, 'w') as outputFile:
for pattern in patterns:
outputFile.write(pattern)
- outputFile.write("\n")
+ outputFile.write('\n')
-if __name__ == "__main__":
+if __name__ == '__main__':
main(sys.argv[1:])
diff --git a/scripts/hiddenapi/signature_patterns_test.py b/scripts/hiddenapi/signature_patterns_test.py
index 3babe54..b59dfd7 100755
--- a/scripts/hiddenapi/signature_patterns_test.py
+++ b/scripts/hiddenapi/signature_patterns_test.py
@@ -13,37 +13,99 @@
# 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.
-
"""Unit tests for signature_patterns.py."""
import io
import unittest
-from signature_patterns import * #pylint: disable=unused-wildcard-import,wildcard-import
+from signature_patterns import * #pylint: disable=unused-wildcard-import,wildcard-import
class TestGeneratedPatterns(unittest.TestCase):
- def produce_patterns_from_string(self, csvdata):
- with io.StringIO(csvdata) as f:
- return produce_patterns_from_stream(f)
- def test_generate(self):
- #pylint: disable=line-too-long
- patterns = self.produce_patterns_from_string(
- '''
+ csvFlags = """
Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V,blocked
Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;,public-api
Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
-'''
- )
- #pylint: enable=line-too-long
+"""
+
+ def produce_patterns_from_string(self,
+ csv,
+ splitPackages=None,
+ packagePrefixes=None):
+ with io.StringIO(csv) as f:
+ return produce_patterns_from_stream(f, splitPackages,
+ packagePrefixes)
+
+ def test_generate_default(self):
+ patterns = self.produce_patterns_from_string(
+ TestGeneratedPatterns.csvFlags)
expected = [
- "java/lang/Character",
- "java/lang/Object",
- "java/lang/ProcessBuilder",
+ 'java/lang/*',
]
self.assertEqual(expected, patterns)
+ def test_generate_split_package(self):
+ patterns = self.produce_patterns_from_string(
+ TestGeneratedPatterns.csvFlags, splitPackages={'java/lang'})
+ expected = [
+ 'java/lang/Character',
+ 'java/lang/Object',
+ 'java/lang/ProcessBuilder',
+ ]
+ self.assertEqual(expected, patterns)
+
+ def test_generate_split_package_wildcard(self):
+ patterns = self.produce_patterns_from_string(
+ TestGeneratedPatterns.csvFlags, splitPackages={'*'})
+ expected = [
+ 'java/lang/Character',
+ 'java/lang/Object',
+ 'java/lang/ProcessBuilder',
+ ]
+ self.assertEqual(expected, patterns)
+
+ def test_generate_package_prefix(self):
+ patterns = self.produce_patterns_from_string(
+ TestGeneratedPatterns.csvFlags, packagePrefixes={'java/lang'})
+ expected = [
+ 'java/lang/**',
+ ]
+ self.assertEqual(expected, patterns)
+
+ def test_generate_package_prefix_top_package(self):
+ patterns = self.produce_patterns_from_string(
+ TestGeneratedPatterns.csvFlags, packagePrefixes={'java'})
+ expected = [
+ 'java/**',
+ ]
+ self.assertEqual(expected, patterns)
+
+ def test_split_package_wildcard_conflicts_with_other_split_packages(self):
+ errors = validate_split_packages({'*', 'java'})
+ expected = [
+ 'split packages are invalid as they contain both the wildcard (*)'
+ ' and specific packages, use the wildcard or specific packages,'
+ ' not a mixture'
+ ]
+ self.assertEqual(expected, errors)
+
+ def test_split_package_wildcard_conflicts_with_package_prefixes(self):
+ errors = validate_package_prefixes({'*'}, packagePrefixes={'java'})
+ expected = [
+ 'split package "*" conflicts with all package prefixes java\n'
+ ' add split_packages:[] to fix',
+ ]
+ self.assertEqual(expected, errors)
+
+ def test_split_package_conflict(self):
+ errors = validate_package_prefixes({'java/split'},
+ packagePrefixes={'java'})
+ expected = [
+ 'split package java.split is matched by package prefix java',
+ ]
+ self.assertEqual(expected, errors)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/scripts/package-check.sh b/scripts/package-check.sh
index d7e602f..9f4a9da 100755
--- a/scripts/package-check.sh
+++ b/scripts/package-check.sh
@@ -42,7 +42,7 @@
fi
# Transform to a slash-separated path and add a trailing slash to enforce
# package name boundary.
- prefixes+=("${package//\./\/}/")
+ prefixes+=("${package//\.//}/")
shift
done
diff --git a/scripts/rbc-run b/scripts/rbc-run
index e2fa6d1..a0907cf 100755
--- a/scripts/rbc-run
+++ b/scripts/rbc-run
@@ -1,16 +1,15 @@
#! /bin/bash
# Convert and run one configuration
-# Args: <product>-<variant>
-[[ $# -eq 1 && "$1" =~ ^(.*)-(.*)$ ]] || { echo Usage: ${0##*/} PRODUCT-VARIANT >&2; exit 1; }
-declare -r product="${BASH_REMATCH[1]:-aosp_arm}"
-declare -r variant="${BASH_REMATCH[2]:-eng}"
+# Args: a product/board makefile optionally followed by additional arguments
+# that will be passed to rbcrun.
+[[ $# -gt 0 && -f "$1" ]] || { echo "Usage: ${0##*/} product.mk [Additional rbcrun arguments]" >&2; exit 1; }
set -eu
declare -r output_root=${OUT_DIR:-out}
declare -r runner="$output_root/soong/.bootstrap/bin/rbcrun"
declare -r converter="$output_root/soong/.bootstrap/bin/mk2rbc"
declare -r launcher=$output_root/launchers/run.rbc
-$converter -mode=write -r --outdir $output_root --launcher=$launcher $product
-printf "#TARGET_PRODUCT=$product TARGET_BUILD_VARIANT=$variant\n"
-env TARGET_PRODUCT=$product TARGET_BUILD_VARIANT=$variant \
- $runner RBC_OUT="make,global" RBC_DEBUG="${RBC_DEBUG:-}" $launcher
+declare -r makefile=$1
+shift
+$converter -mode=write -r --outdir $output_root --launcher=$launcher $makefile
+$runner RBC_OUT="make,global" RBC_DEBUG="${RBC_DEBUG:-}" $@ $launcher
diff --git a/sdk/Android.bp b/sdk/Android.bp
index acb9dbb..f42b478 100644
--- a/sdk/Android.bp
+++ b/sdk/Android.bp
@@ -16,6 +16,7 @@
],
srcs: [
"bp.go",
+ "build_release.go",
"exports.go",
"member_trait.go",
"member_type.go",
@@ -25,6 +26,7 @@
testSrcs: [
"bootclasspath_fragment_sdk_test.go",
"bp_test.go",
+ "build_release_test.go",
"cc_sdk_test.go",
"compat_config_sdk_test.go",
"exports_test.go",
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index e1ae474..ff2af43 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -138,8 +138,8 @@
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
signature_patterns: "hiddenapi/signature-patterns.csv",
- stub_flags: "hiddenapi/filtered-stub-flags.csv",
- all_flags: "hiddenapi/filtered-flags.csv",
+ filtered_stub_flags: "hiddenapi/filtered-stub-flags.csv",
+ filtered_flags: "hiddenapi/filtered-flags.csv",
},
}
@@ -166,8 +166,8 @@
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
signature_patterns: "hiddenapi/signature-patterns.csv",
- stub_flags: "hiddenapi/filtered-stub-flags.csv",
- all_flags: "hiddenapi/filtered-flags.csv",
+ filtered_stub_flags: "hiddenapi/filtered-stub-flags.csv",
+ filtered_flags: "hiddenapi/filtered-flags.csv",
},
}
@@ -339,8 +339,8 @@
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
signature_patterns: "hiddenapi/signature-patterns.csv",
- stub_flags: "hiddenapi/filtered-stub-flags.csv",
- all_flags: "hiddenapi/filtered-flags.csv",
+ filtered_stub_flags: "hiddenapi/filtered-stub-flags.csv",
+ filtered_flags: "hiddenapi/filtered-flags.csv",
},
}
@@ -424,8 +424,8 @@
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
signature_patterns: "hiddenapi/signature-patterns.csv",
- stub_flags: "hiddenapi/filtered-stub-flags.csv",
- all_flags: "hiddenapi/filtered-flags.csv",
+ filtered_stub_flags: "hiddenapi/filtered-stub-flags.csv",
+ filtered_flags: "hiddenapi/filtered-flags.csv",
},
}
@@ -649,8 +649,8 @@
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
signature_patterns: "hiddenapi/signature-patterns.csv",
- stub_flags: "hiddenapi/filtered-stub-flags.csv",
- all_flags: "hiddenapi/filtered-flags.csv",
+ filtered_stub_flags: "hiddenapi/filtered-stub-flags.csv",
+ filtered_flags: "hiddenapi/filtered-flags.csv",
},
}
@@ -852,8 +852,8 @@
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
signature_patterns: "hiddenapi/signature-patterns.csv",
- stub_flags: "hiddenapi/filtered-stub-flags.csv",
- all_flags: "hiddenapi/filtered-flags.csv",
+ filtered_stub_flags: "hiddenapi/filtered-stub-flags.csv",
+ filtered_flags: "hiddenapi/filtered-flags.csv",
},
}
diff --git a/sdk/build_release.go b/sdk/build_release.go
new file mode 100644
index 0000000..a3f0899
--- /dev/null
+++ b/sdk/build_release.go
@@ -0,0 +1,324 @@
+// 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 sdk
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+// Supports customizing sdk snapshot output based on target build release.
+
+// buildRelease represents the version of a build system used to create a specific release.
+//
+// The name of the release, is the same as the code for the dessert release, e.g. S, T, etc.
+type buildRelease struct {
+ // The name of the release, e.g. S, T, etc.
+ name string
+
+ // The index of this structure within the buildReleases list.
+ ordinal int
+}
+
+// String returns the name of the build release.
+func (s *buildRelease) String() string {
+ return s.name
+}
+
+// buildReleaseSet represents a set of buildRelease objects.
+type buildReleaseSet struct {
+ // Set of *buildRelease represented as a map from *buildRelease to struct{}.
+ contents map[*buildRelease]struct{}
+}
+
+// addItem adds a build release to the set.
+func (s *buildReleaseSet) addItem(release *buildRelease) {
+ s.contents[release] = struct{}{}
+}
+
+// addRange adds all the build releases from start (inclusive) to end (inclusive).
+func (s *buildReleaseSet) addRange(start *buildRelease, end *buildRelease) {
+ for i := start.ordinal; i <= end.ordinal; i += 1 {
+ s.addItem(buildReleases[i])
+ }
+}
+
+// contains returns true if the set contains the specified build release.
+func (s *buildReleaseSet) contains(release *buildRelease) bool {
+ _, ok := s.contents[release]
+ return ok
+}
+
+// String returns a string representation of the set, sorted from earliest to latest release.
+func (s *buildReleaseSet) String() string {
+ list := []string{}
+ for _, release := range buildReleases {
+ if _, ok := s.contents[release]; ok {
+ list = append(list, release.name)
+ }
+ }
+ return fmt.Sprintf("[%s]", strings.Join(list, ","))
+}
+
+var (
+ // nameToBuildRelease contains a map from name to build release.
+ nameToBuildRelease = map[string]*buildRelease{}
+
+ // buildReleases lists all the available build releases.
+ buildReleases = []*buildRelease{}
+
+ // allBuildReleaseSet is the set of all build releases.
+ allBuildReleaseSet = &buildReleaseSet{contents: map[*buildRelease]struct{}{}}
+
+ // Add the build releases from oldest to newest.
+ buildReleaseS = initBuildRelease("S")
+ buildReleaseT = initBuildRelease("T")
+)
+
+// initBuildRelease creates a new build release with the specified name.
+func initBuildRelease(name string) *buildRelease {
+ ordinal := len(nameToBuildRelease)
+ release := &buildRelease{name: name, ordinal: ordinal}
+ nameToBuildRelease[name] = release
+ buildReleases = append(buildReleases, release)
+ allBuildReleaseSet.addItem(release)
+ return release
+}
+
+// latestBuildRelease returns the latest build release, i.e. the last one added.
+func latestBuildRelease() *buildRelease {
+ return buildReleases[len(buildReleases)-1]
+}
+
+// nameToRelease maps from build release name to the corresponding build release (if it exists) or
+// the error if it does not.
+func nameToRelease(name string) (*buildRelease, error) {
+ if r, ok := nameToBuildRelease[name]; ok {
+ return r, nil
+ }
+
+ return nil, fmt.Errorf("unknown release %q, expected one of %s", name, allBuildReleaseSet)
+}
+
+// parseBuildReleaseSet parses a build release set string specification into a build release set.
+//
+// The specification consists of one of the following:
+// * a single build release name, e.g. S, T, etc.
+// * a closed range (inclusive to inclusive), e.g. S-T
+// * an open range, e.g. T+.
+//
+// This returns the set if the specification was valid or an error.
+func parseBuildReleaseSet(specification string) (*buildReleaseSet, error) {
+ set := &buildReleaseSet{contents: map[*buildRelease]struct{}{}}
+
+ if strings.HasSuffix(specification, "+") {
+ rangeStart := strings.TrimSuffix(specification, "+")
+ start, err := nameToRelease(rangeStart)
+ if err != nil {
+ return nil, err
+ }
+ end := latestBuildRelease()
+ set.addRange(start, end)
+ } else if strings.Contains(specification, "-") {
+ limits := strings.SplitN(specification, "-", 2)
+ start, err := nameToRelease(limits[0])
+ if err != nil {
+ return nil, err
+ }
+
+ end, err := nameToRelease(limits[1])
+ if err != nil {
+ return nil, err
+ }
+
+ if start.ordinal > end.ordinal {
+ return nil, fmt.Errorf("invalid closed range, start release %q is later than end release %q", start.name, end.name)
+ }
+
+ set.addRange(start, end)
+ } else {
+ release, err := nameToRelease(specification)
+ if err != nil {
+ return nil, err
+ }
+ set.addItem(release)
+ }
+
+ return set, nil
+}
+
+// Given a set of properties (struct value), set the value of a field within that struct (or one of
+// its embedded structs) to its zero value.
+type fieldPrunerFunc func(structValue reflect.Value)
+
+// A property that can be cleared by a propertyPruner.
+type prunerProperty struct {
+ // The name of the field for this property. It is a "."-separated path for fields in non-anonymous
+ // sub-structs.
+ name string
+
+ // Sets the associated field to its zero value.
+ prunerFunc fieldPrunerFunc
+}
+
+// propertyPruner provides support for pruning (i.e. setting to their zero value) properties from
+// a properties structure.
+type propertyPruner struct {
+ // The properties that the pruner will clear.
+ properties []prunerProperty
+}
+
+// gatherFields recursively processes the supplied structure and a nested structures, selecting the
+// fields that require pruning and populates the propertyPruner.properties with the information
+// needed to prune those fields.
+//
+// containingStructAccessor is a func that if given an object will return a field whose value is
+// of the supplied structType. It is nil on initial entry to this method but when this method is
+// called recursively on a field that is a nested structure containingStructAccessor is set to a
+// func that provides access to the field's value.
+//
+// namePrefix is the prefix to the fields that are being visited. It is "" on initial entry to this
+// method but when this method is called recursively on a field that is a nested structure
+// namePrefix is the result of appending the field name (plus a ".") to the previous name prefix.
+// Unless the field is anonymous in which case it is passed through unchanged.
+//
+// selector is a func that will select whether the supplied field requires pruning or not. If it
+// returns true then the field will be added to those to be pruned, otherwise it will not.
+func (p *propertyPruner) gatherFields(structType reflect.Type, containingStructAccessor fieldAccessorFunc, namePrefix string, selector fieldSelectorFunc) {
+ for f := 0; f < structType.NumField(); f++ {
+ field := structType.Field(f)
+ if field.PkgPath != "" {
+ // Ignore unexported fields.
+ continue
+ }
+
+ // Save a copy of the field index for use in the function.
+ fieldIndex := f
+
+ name := namePrefix + field.Name
+
+ fieldGetter := func(container reflect.Value) reflect.Value {
+ if containingStructAccessor != nil {
+ // This is an embedded structure so first access the field for the embedded
+ // structure.
+ container = containingStructAccessor(container)
+ }
+
+ // Skip through interface and pointer values to find the structure.
+ container = getStructValue(container)
+
+ defer func() {
+ if r := recover(); r != nil {
+ panic(fmt.Errorf("%s for fieldIndex %d of field %s of container %#v", r, fieldIndex, name, container.Interface()))
+ }
+ }()
+
+ // Return the field.
+ return container.Field(fieldIndex)
+ }
+
+ zeroValue := reflect.Zero(field.Type)
+ fieldPruner := func(container reflect.Value) {
+ if containingStructAccessor != nil {
+ // This is an embedded structure so first access the field for the embedded
+ // structure.
+ container = containingStructAccessor(container)
+ }
+
+ // Skip through interface and pointer values to find the structure.
+ container = getStructValue(container)
+
+ defer func() {
+ if r := recover(); r != nil {
+ panic(fmt.Errorf("%s for fieldIndex %d of field %s of container %#v", r, fieldIndex, name, container.Interface()))
+ }
+ }()
+
+ // Set the field.
+ container.Field(fieldIndex).Set(zeroValue)
+ }
+
+ if selector(name, field) {
+ property := prunerProperty{
+ name,
+ fieldPruner,
+ }
+ p.properties = append(p.properties, property)
+ } else if field.Type.Kind() == reflect.Struct {
+ // Gather fields from the nested or embedded structure.
+ var subNamePrefix string
+ if field.Anonymous {
+ subNamePrefix = namePrefix
+ } else {
+ subNamePrefix = name + "."
+ }
+ p.gatherFields(field.Type, fieldGetter, subNamePrefix, selector)
+ }
+ }
+}
+
+// pruneProperties will prune (set to zero value) any properties in the supplied struct.
+//
+// The struct must be of the same type as was originally passed to newPropertyPruner to create this
+// propertyPruner.
+func (p *propertyPruner) pruneProperties(propertiesStruct interface{}) {
+ structValue := reflect.ValueOf(propertiesStruct)
+ for _, property := range p.properties {
+ property.prunerFunc(structValue)
+ }
+}
+
+// fieldSelectorFunc is called to select whether a specific field should be pruned or not.
+// name is the name of the field, including any prefixes from containing str
+type fieldSelectorFunc func(name string, field reflect.StructField) bool
+
+// newPropertyPruner creates a new property pruner for the structure type for the supplied
+// properties struct.
+//
+// The returned pruner can be used on any properties structure of the same type as the supplied set
+// of properties.
+func newPropertyPruner(propertiesStruct interface{}, selector fieldSelectorFunc) *propertyPruner {
+ structType := getStructValue(reflect.ValueOf(propertiesStruct)).Type()
+ pruner := &propertyPruner{}
+ pruner.gatherFields(structType, nil, "", selector)
+ return pruner
+}
+
+// newPropertyPrunerByBuildRelease creates a property pruner that will clear any properties in the
+// structure which are not supported by the specified target build release.
+//
+// A property is pruned if its field has a tag of the form:
+// `supported_build_releases:"<build-release-set>"`
+// and the resulting build release set does not contain the target build release. Properties that
+// have no such tag are assumed to be supported by all releases.
+func newPropertyPrunerByBuildRelease(propertiesStruct interface{}, targetBuildRelease *buildRelease) *propertyPruner {
+ return newPropertyPruner(propertiesStruct, func(name string, field reflect.StructField) bool {
+ if supportedBuildReleases, ok := field.Tag.Lookup("supported_build_releases"); ok {
+ set, err := parseBuildReleaseSet(supportedBuildReleases)
+ if err != nil {
+ panic(fmt.Errorf("invalid `supported_build_releases` tag on %s of %T: %s", name, propertiesStruct, err))
+ }
+
+ // If the field does not support tha target release then prune it.
+ return !set.contains(targetBuildRelease)
+
+ } else {
+ // Any untagged fields are assumed to be supported by all build releases so should never be
+ // pruned.
+ return false
+ }
+ })
+}
diff --git a/sdk/build_release_test.go b/sdk/build_release_test.go
new file mode 100644
index 0000000..dff276d
--- /dev/null
+++ b/sdk/build_release_test.go
@@ -0,0 +1,185 @@
+// 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 sdk
+
+import (
+ "fmt"
+ "testing"
+
+ "android/soong/android"
+)
+
+// Tests for build_release.go
+
+var (
+ // Some additional test specific releases that are added after the currently supported ones and
+ // so are treated as being for future releases.
+ buildReleaseFuture1 = initBuildRelease("F1")
+ buildReleaseFuture2 = initBuildRelease("F2")
+)
+
+func TestNameToRelease(t *testing.T) {
+ t.Run("single release", func(t *testing.T) {
+ release, err := nameToRelease("S")
+ android.AssertDeepEquals(t, "errors", nil, err)
+ android.AssertDeepEquals(t, "release", buildReleaseS, release)
+ })
+ t.Run("invalid release", func(t *testing.T) {
+ release, err := nameToRelease("A")
+ android.AssertDeepEquals(t, "release", (*buildRelease)(nil), release)
+ // Uses a wildcard in the error message to allow for additional build releases to be added to
+ // the supported set without breaking this test.
+ android.FailIfNoMatchingErrors(t, `unknown release "A", expected one of \[S,T.*,F1,F2\]`, []error{err})
+ })
+}
+
+func TestParseBuildReleaseSet(t *testing.T) {
+ t.Run("single release", func(t *testing.T) {
+ set, err := parseBuildReleaseSet("S")
+ android.AssertDeepEquals(t, "errors", nil, err)
+ android.AssertStringEquals(t, "set", "[S]", set.String())
+ })
+ t.Run("open range", func(t *testing.T) {
+ set, err := parseBuildReleaseSet("F1+")
+ android.AssertDeepEquals(t, "errors", nil, err)
+ android.AssertStringEquals(t, "set", "[F1,F2]", set.String())
+ })
+ t.Run("closed range", func(t *testing.T) {
+ set, err := parseBuildReleaseSet("S-F1")
+ android.AssertDeepEquals(t, "errors", nil, err)
+ android.AssertStringEquals(t, "set", "[S,T,F1]", set.String())
+ })
+ invalidAReleaseMessage := `unknown release "A", expected one of ` + allBuildReleaseSet.String()
+ t.Run("invalid release", func(t *testing.T) {
+ set, err := parseBuildReleaseSet("A")
+ android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set)
+ android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), invalidAReleaseMessage)
+ })
+ t.Run("invalid release in open range", func(t *testing.T) {
+ set, err := parseBuildReleaseSet("A+")
+ android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set)
+ android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), invalidAReleaseMessage)
+ })
+ t.Run("invalid release in closed range start", func(t *testing.T) {
+ set, err := parseBuildReleaseSet("A-S")
+ android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set)
+ android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), invalidAReleaseMessage)
+ })
+ t.Run("invalid release in closed range end", func(t *testing.T) {
+ set, err := parseBuildReleaseSet("T-A")
+ android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set)
+ android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), invalidAReleaseMessage)
+ })
+ t.Run("invalid closed range reversed", func(t *testing.T) {
+ set, err := parseBuildReleaseSet("F1-S")
+ android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set)
+ android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), `invalid closed range, start release "F1" is later than end release "S"`)
+ })
+}
+
+func TestBuildReleaseSetContains(t *testing.T) {
+ t.Run("contains", func(t *testing.T) {
+ set, _ := parseBuildReleaseSet("F1-F2")
+ android.AssertBoolEquals(t, "set contains F1", true, set.contains(buildReleaseFuture1))
+ android.AssertBoolEquals(t, "set does not contain S", false, set.contains(buildReleaseS))
+ android.AssertBoolEquals(t, "set contains F2", true, set.contains(buildReleaseFuture2))
+ android.AssertBoolEquals(t, "set does not contain T", false, set.contains(buildReleaseT))
+ })
+}
+
+func TestPropertyPrunerInvalidTag(t *testing.T) {
+ type brokenStruct struct {
+ Broken string `supported_build_releases:"A"`
+ }
+ type containingStruct struct {
+ Nested brokenStruct
+ }
+
+ t.Run("broken struct", func(t *testing.T) {
+ android.AssertPanicMessageContains(t, "error", "invalid `supported_build_releases` tag on Broken of *sdk.brokenStruct: unknown release \"A\"", func() {
+ newPropertyPrunerByBuildRelease(&brokenStruct{}, buildReleaseS)
+ })
+ })
+
+ t.Run("nested broken struct", func(t *testing.T) {
+ android.AssertPanicMessageContains(t, "error", "invalid `supported_build_releases` tag on Nested.Broken of *sdk.containingStruct: unknown release \"A\"", func() {
+ newPropertyPrunerByBuildRelease(&containingStruct{}, buildReleaseS)
+ })
+ })
+}
+
+func TestPropertyPrunerByBuildRelease(t *testing.T) {
+ type nested struct {
+ F1_only string `supported_build_releases:"F1"`
+ }
+
+ type testBuildReleasePruner struct {
+ Default string
+ S_and_T_only string `supported_build_releases:"S-T"`
+ T_later string `supported_build_releases:"T+"`
+ Nested nested
+ }
+
+ input := testBuildReleasePruner{
+ Default: "Default",
+ S_and_T_only: "S_and_T_only",
+ T_later: "T_later",
+ Nested: nested{
+ F1_only: "F1_only",
+ },
+ }
+
+ t.Run("target S", func(t *testing.T) {
+ testStruct := input
+ pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseS)
+ pruner.pruneProperties(&testStruct)
+
+ expected := input
+ expected.T_later = ""
+ expected.Nested.F1_only = ""
+ android.AssertDeepEquals(t, "test struct", expected, testStruct)
+ })
+
+ t.Run("target T", func(t *testing.T) {
+ testStruct := input
+ pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseT)
+ pruner.pruneProperties(&testStruct)
+
+ expected := input
+ expected.Nested.F1_only = ""
+ android.AssertDeepEquals(t, "test struct", expected, testStruct)
+ })
+
+ t.Run("target F1", func(t *testing.T) {
+ testStruct := input
+ pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseFuture1)
+ pruner.pruneProperties(&testStruct)
+
+ expected := input
+ expected.S_and_T_only = ""
+ android.AssertDeepEquals(t, "test struct", expected, testStruct)
+ })
+
+ t.Run("target F2", func(t *testing.T) {
+ testStruct := input
+ pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseFuture2)
+ pruner.pruneProperties(&testStruct)
+
+ expected := input
+ expected.S_and_T_only = ""
+ expected.Nested.F1_only = ""
+ android.AssertDeepEquals(t, "test struct", expected, testStruct)
+ })
+}
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 85e3d87..83294f6 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -21,6 +21,7 @@
"testing"
"android/soong/android"
+ "android/soong/java"
"github.com/google/blueprint/proptools"
)
@@ -706,4 +707,86 @@
snapshotTestPreparer(checkSnapshotWithoutSource, android.FixtureWithRootAndroidBp(bp)),
)
})
+
+ t.Run("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE=S", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForSdkTestWithJava,
+ java.PrepareForTestWithJavaDefaultModules,
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithLastReleaseApis("mysdklibrary"),
+ android.FixtureWithRootAndroidBp(`
+ sdk {
+ name: "mysdk",
+ bootclasspath_fragments: ["mybootclasspathfragment"],
+ }
+
+ bootclasspath_fragment {
+ name: "mybootclasspathfragment",
+ apex_available: ["myapex"],
+ contents: ["mysdklibrary"],
+ }
+
+ java_sdk_library {
+ name: "mysdklibrary",
+ srcs: ["Test.java"],
+ compile_dex: true,
+ public: {enabled: true},
+ permitted_packages: ["mysdklibrary"],
+ }
+ `),
+ android.FixtureMergeEnv(map[string]string{
+ "SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": "S",
+ }),
+ ).RunTest(t)
+
+ CheckSnapshot(t, result, "mysdk", "",
+ checkUnversionedAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+prebuilt_bootclasspath_fragment {
+ name: "mybootclasspathfragment",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["myapex"],
+ contents: ["mysdklibrary"],
+ hidden_api: {
+ annotation_flags: "hiddenapi/annotation-flags.csv",
+ metadata: "hiddenapi/metadata.csv",
+ index: "hiddenapi/index.csv",
+ stub_flags: "hiddenapi/stub-flags.csv",
+ all_flags: "hiddenapi/all-flags.csv",
+ },
+}
+
+java_sdk_library_import {
+ name: "mysdklibrary",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ shared_library: true,
+ compile_dex: true,
+ permitted_packages: ["mysdklibrary"],
+ public: {
+ jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
+ stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
+ current_api: "sdk_library/public/mysdklibrary.txt",
+ removed_api: "sdk_library/public/mysdklibrary-removed.txt",
+ sdk_version: "current",
+ },
+}
+`),
+
+ checkAllCopyRules(`
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
+.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
+`),
+ )
+ })
+
}
diff --git a/sdk/testing.go b/sdk/testing.go
index 3254cf9..294f1a5 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -136,6 +136,7 @@
androidUnversionedBpContents: sdk.GetUnversionedAndroidBpContentsForTests(),
androidVersionedBpContents: sdk.GetVersionedAndroidBpContentsForTests(),
snapshotTestCustomizations: map[snapshotTest]*snapshotTestCustomization{},
+ targetBuildRelease: sdk.builderForTests.targetBuildRelease,
}
buildParams := sdk.BuildParamsForTests()
@@ -253,6 +254,13 @@
}
fs[filepath.Join(snapshotSubDir, "Android.bp")] = []byte(snapshotBuildInfo.androidBpContents)
+ // If the generated snapshot builders not for the current release then it cannot be loaded by
+ // the current release.
+ currentBuildRelease := latestBuildRelease()
+ if snapshotBuildInfo.targetBuildRelease != currentBuildRelease {
+ return
+ }
+
// The preparers from the original source fixture.
sourcePreparers := result.Preparer()
@@ -476,6 +484,9 @@
// The final output zip.
outputZip string
+ // The target build release.
+ targetBuildRelease *buildRelease
+
// The test specific customizations for each snapshot test.
snapshotTestCustomizations map[snapshotTest]*snapshotTestCustomization
}
diff --git a/sdk/update.go b/sdk/update.go
index 3246832..389e845 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -81,6 +81,19 @@
// snapshot module only. The zip file containing the generated snapshot will be
// <sdk-name>-<number>.zip.
//
+// SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE
+// This allows the target build release (i.e. the release version of the build within which
+// the snapshot will be used) of the snapshot to be specified. If unspecified then it defaults
+// to the current build release version. Otherwise, it must be the name of one of the build
+// releases defined in nameToBuildRelease, e.g. S, T, etc..
+//
+// The generated snapshot must only be used in the specified target release. If the target
+// build release is not the current build release then the generated Android.bp file not be
+// checked for compatibility.
+//
+// e.g. if setting SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE=S will cause the generated snapshot
+// to be compatible with S.
+//
var pctx = android.NewPackageContext("android/soong/sdk")
@@ -358,6 +371,14 @@
snapshotZipFileSuffix = "-" + version
}
+ currentBuildRelease := latestBuildRelease()
+ targetBuildReleaseEnv := config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE", currentBuildRelease.name)
+ targetBuildRelease, err := nameToRelease(targetBuildReleaseEnv)
+ if err != nil {
+ ctx.ModuleErrorf("invalid SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE: %s", err)
+ targetBuildRelease = currentBuildRelease
+ }
+
builder := &snapshotBuilder{
ctx: ctx,
sdk: s,
@@ -369,6 +390,7 @@
prebuiltModules: make(map[string]*bpModule),
allMembersByName: allMembersByName,
exportedMembersByName: exportedMembersByName,
+ targetBuildRelease: targetBuildRelease,
}
s.builderForTests = builder
@@ -449,7 +471,11 @@
generateBpContents(&bp.generatedContents, bpFile)
contents := bp.content.String()
- syntaxCheckSnapshotBpFile(ctx, contents)
+ // If the snapshot is being generated for the current build release then check the syntax to make
+ // sure that it is compatible.
+ if targetBuildRelease == currentBuildRelease {
+ syntaxCheckSnapshotBpFile(ctx, contents)
+ }
bp.build(pctx, ctx, nil)
@@ -1051,6 +1077,9 @@
// The set of exported members by name.
exportedMembersByName map[string]struct{}
+
+ // The target build release for which the snapshot is to be generated.
+ targetBuildRelease *buildRelease
}
func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) {
@@ -1426,6 +1455,16 @@
return osInfo
}
+func (osInfo *osTypeSpecificInfo) pruneUnsupportedProperties(pruner *propertyPruner) {
+ if len(osInfo.archInfos) == 0 {
+ pruner.pruneProperties(osInfo.Properties)
+ } else {
+ for _, archInfo := range osInfo.archInfos {
+ archInfo.pruneUnsupportedProperties(pruner)
+ }
+ }
+}
+
// Optimize the properties by extracting common properties from arch type specific
// properties into os type specific properties.
func (osInfo *osTypeSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) {
@@ -1635,6 +1674,16 @@
return linkType
}
+func (archInfo *archTypeSpecificInfo) pruneUnsupportedProperties(pruner *propertyPruner) {
+ if len(archInfo.imageVariantInfos) == 0 {
+ pruner.pruneProperties(archInfo.Properties)
+ } else {
+ for _, imageVariantInfo := range archInfo.imageVariantInfos {
+ imageVariantInfo.pruneUnsupportedProperties(pruner)
+ }
+ }
+}
+
// Optimize the properties by extracting common properties from link type specific
// properties into arch type specific properties.
func (archInfo *archTypeSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) {
@@ -1732,6 +1781,16 @@
return imageInfo
}
+func (imageInfo *imageVariantSpecificInfo) pruneUnsupportedProperties(pruner *propertyPruner) {
+ if len(imageInfo.linkInfos) == 0 {
+ pruner.pruneProperties(imageInfo.Properties)
+ } else {
+ for _, linkInfo := range imageInfo.linkInfos {
+ linkInfo.pruneUnsupportedProperties(pruner)
+ }
+ }
+}
+
// Optimize the properties by extracting common properties from link type specific
// properties into arch type specific properties.
func (imageInfo *imageVariantSpecificInfo) optimizeProperties(ctx *memberContext, commonValueExtractor *commonValueExtractor) {
@@ -1798,6 +1857,10 @@
addSdkMemberPropertiesToSet(ctx, l.Properties, linkPropertySet)
}
+func (l *linkTypeSpecificInfo) pruneUnsupportedProperties(pruner *propertyPruner) {
+ pruner.pruneProperties(l.Properties)
+}
+
func (l *linkTypeSpecificInfo) String() string {
return fmt.Sprintf("LinkType{%s}", l.linkType)
}
@@ -1837,12 +1900,12 @@
memberType := member.memberType
// Do not add the prefer property if the member snapshot module is a source module type.
+ config := ctx.sdkMemberContext.Config()
if !memberType.UsesSourceModuleTypeInSnapshot() {
// Set the prefer based on the environment variable. This is a temporary work around to allow a
// snapshot to be created that sets prefer: true.
// TODO(b/174997203): Remove once the ability to select the modules to prefer can be done
// dynamically at build time not at snapshot generation time.
- config := ctx.sdkMemberContext.Config()
prefer := config.IsEnvTrue("SOONG_SDK_SNAPSHOT_PREFER")
// Set prefer. Setting this to false is not strictly required as that is the default but it does
@@ -1884,6 +1947,11 @@
commonProperties := variantPropertiesFactory()
commonProperties.Base().Os = android.CommonOS
+ // Create a property pruner that will prune any properties unsupported by the target build
+ // release.
+ targetBuildRelease := ctx.builder.targetBuildRelease
+ unsupportedPropertyPruner := newPropertyPrunerByBuildRelease(commonProperties, targetBuildRelease)
+
// Create common value extractor that can be used to optimize the properties.
commonValueExtractor := newCommonValueExtractor(commonProperties)
@@ -1898,6 +1966,8 @@
// independent properties structs.
osSpecificPropertiesContainers = append(osSpecificPropertiesContainers, osInfo)
+ osInfo.pruneUnsupportedProperties(unsupportedPropertyPruner)
+
// Optimize the properties across all the variants for a specific os type.
osInfo.optimizeProperties(ctx, commonValueExtractor)
}
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index db66ae2..b22a5b7 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -548,7 +548,7 @@
Rule_class: "sh_binary",
}
- ctx.CreateBazelTargetModule(m.Name(), props, attrs)
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
}
var Bool = proptools.Bool
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 3d16073..afec829 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -163,6 +163,7 @@
"AUX_OS_VARIANT_LIST",
"PRODUCT_SOONG_NAMESPACES",
"SOONG_SDK_SNAPSHOT_PREFER",
+ "SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE",
"SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR",
"SOONG_SDK_SNAPSHOT_VERSION",
}