aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-03-02 15:20:01 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-03-02 15:20:01 +0000
commitb856a37c33bfc26f8888466516627d12533e5456 (patch)
tree3d64e0b40800a07374d875ba9ffee3367e13007f
parente308444ef9a0f76a03faf490d03da5b0976f34d7 (diff)
parent7720f5704c3d65f2d70212664d3a80d98dceeb34 (diff)
downloadsoong-platform-tools-34.0.1.tar.gz
Snap for 9679998 from 7720f5704c3d65f2d70212664d3a80d98dceeb34 to sdk-releaseplatform-tools-34.0.1
Change-Id: I199aa775e8d963d33070cfaa899450f52e57c382
-rw-r--r--OWNERS3
-rw-r--r--android/allowlists/allowlists.go88
-rw-r--r--android/androidmk.go3
-rw-r--r--android/apex.go2
-rw-r--r--android/api_levels.go84
-rw-r--r--android/bazel.go16
-rw-r--r--android/bazel_handler.go465
-rw-r--r--android/bazel_handler_test.go121
-rw-r--r--android/config.go18
-rw-r--r--android/defaults.go8
-rw-r--r--android/defs.go8
-rw-r--r--android/filegroup.go4
-rw-r--r--android/module.go9
-rw-r--r--android/mutator.go23
-rw-r--r--android/mutator_test.go20
-rw-r--r--android/neverallow.go2
-rw-r--r--android/packaging.go2
-rw-r--r--android/paths.go44
-rw-r--r--android/phony.go2
-rw-r--r--android/sdk_version.go24
-rw-r--r--android/soongconfig/modules.go17
-rw-r--r--android/test_suites.go2
-rw-r--r--android/util.go58
-rw-r--r--android/util_test.go62
-rw-r--r--android/variable.go6
-rw-r--r--android_sdk/sdk_repo_host.go5
-rw-r--r--apex/OWNERS1
-rw-r--r--apex/androidmk.go50
-rw-r--r--apex/apex.go102
-rw-r--r--apex/apex_singleton.go10
-rw-r--r--apex/apex_test.go643
-rw-r--r--apex/bootclasspath_fragment_test.go6
-rw-r--r--apex/bp2build.go10
-rw-r--r--apex/builder.go68
-rw-r--r--apex/systemserver_classpath_fragment_test.go149
-rw-r--r--apex/vndk.go4
-rw-r--r--bazel/Android.bp1
-rw-r--r--bazel/aquery.go422
-rw-r--r--bazel/aquery_test.go141
-rw-r--r--bazel/bazel_proxy.go219
-rw-r--r--bazel/cquery/request_type.go18
-rw-r--r--bp2build/bp2build.go70
-rw-r--r--bp2build/build_conversion.go2
-rw-r--r--bp2build/bzl_conversion.go6
-rw-r--r--bp2build/cc_binary_conversion_test.go6
-rw-r--r--bp2build/cc_library_conversion_test.go112
-rw-r--r--bp2build/cc_library_shared_conversion_test.go17
-rw-r--r--bp2build/configurability.go2
-rw-r--r--bp2build/conversion.go17
-rw-r--r--bp2build/conversion_test.go14
-rw-r--r--bp2build/java_sdk_library_conversion_test.go148
-rw-r--r--bp2build/metrics.go2
-rw-r--r--bp2build/symlink_forest.go228
-rw-r--r--bp2build/testing.go6
-rw-r--r--cc/OWNERS3
-rw-r--r--cc/androidmk.go13
-rw-r--r--cc/binary.go19
-rw-r--r--cc/binary_test.go41
-rw-r--r--cc/bp2build.go102
-rw-r--r--cc/cc.go89
-rw-r--r--cc/cc_test.go89
-rw-r--r--cc/config/global.go16
-rw-r--r--cc/config/riscv64_device.go4
-rw-r--r--cc/fuzz.go92
-rw-r--r--cc/library.go53
-rw-r--r--cc/library_headers.go10
-rw-r--r--cc/library_sdk_member.go2
-rw-r--r--cc/library_test.go122
-rw-r--r--cc/linkable.go15
-rw-r--r--cc/linker.go31
-rw-r--r--cc/lto_test.go64
-rw-r--r--cc/ndk_api_coverage_parser/OWNERS1
-rw-r--r--cc/object.go4
-rw-r--r--cc/prebuilt.go33
-rw-r--r--cc/prebuilt_test.go69
-rw-r--r--cc/sanitize.go4
-rw-r--r--cc/sdk.go11
-rw-r--r--cc/sdk_test.go92
-rw-r--r--cc/stub_library.go2
-rw-r--r--cc/test.go6
-rw-r--r--cc/util.go2
-rw-r--r--cc/vndk.go2
-rw-r--r--cmd/multiproduct_kati/main.go3
-rw-r--r--cmd/soong_build/main.go5
-rw-r--r--cmd/soong_ui/main.go6
-rw-r--r--compliance/OWNERS8
-rw-r--r--dexpreopt/OWNERS1
-rw-r--r--dexpreopt/dexpreopt.go4
-rw-r--r--docs/OWNERS3
-rw-r--r--filesystem/filesystem_test.go37
-rw-r--r--fuzz/fuzz_common.go263
-rw-r--r--java/OWNERS4
-rw-r--r--java/aar.go27
-rwxr-xr-xjava/app.go10
-rw-r--r--java/app_test.go21
-rw-r--r--java/base.go24
-rw-r--r--java/bootclasspath_fragment.go6
-rw-r--r--java/classpath_fragment.go2
-rw-r--r--java/config/config.go1
-rw-r--r--java/dex.go33
-rw-r--r--java/dex_test.go1
-rw-r--r--java/dexpreopt.go94
-rw-r--r--java/dexpreopt_bootjars.go65
-rw-r--r--java/dexpreopt_config.go67
-rw-r--r--java/dexpreopt_config_test.go2
-rw-r--r--java/dexpreopt_config_testing.go485
-rw-r--r--java/droiddoc.go17
-rw-r--r--java/hiddenapi.go29
-rw-r--r--java/hiddenapi_modular.go12
-rw-r--r--java/java.go90
-rw-r--r--java/java_test.go80
-rw-r--r--java/lint.go156
-rw-r--r--java/lint_test.go172
-rw-r--r--java/platform_bootclasspath.go41
-rw-r--r--java/prebuilt_apis.go4
-rw-r--r--java/robolectric.go3
-rw-r--r--java/sdk.go10
-rw-r--r--java/sdk_library.go80
-rw-r--r--java/sdk_library_test.go1
-rw-r--r--java/testing.go2
-rw-r--r--licenses/OWNERS2
-rw-r--r--linkerconfig/proto/OWNERS3
-rw-r--r--python/python.go2
-rw-r--r--rust/androidmk.go9
-rw-r--r--rust/bindgen.go4
-rw-r--r--rust/builder.go10
-rw-r--r--rust/compiler.go9
-rw-r--r--rust/config/global.go2
-rw-r--r--rust/config/x86_linux_bionic_host.go4
-rw-r--r--rust/coverage.go13
-rw-r--r--rust/fuzz.go121
-rw-r--r--rust/image_test.go30
-rw-r--r--rust/rust.go41
-rw-r--r--scripts/OWNERS4
-rw-r--r--scripts/check_boot_jars/package_allowed_list.txt1
-rw-r--r--scripts/test_config_fixer.py17
-rw-r--r--scripts/test_config_fixer_test.py36
-rw-r--r--sdk/bootclasspath_fragment_sdk_test.go36
-rw-r--r--sdk/java_sdk_test.go3
-rw-r--r--sdk/systemserverclasspath_fragment_sdk_test.go60
-rw-r--r--sdk/update.go6
-rw-r--r--starlark_fmt/format.go11
-rwxr-xr-xtests/bootstrap_test.sh6
-rwxr-xr-xtests/bp2build_bazel_test.sh107
-rwxr-xr-xtests/dcla_apex_comparison_test.sh138
-rwxr-xr-xtests/persistent_bazel_test.sh83
-rwxr-xr-xtests/run_integration_tests.sh5
-rw-r--r--ui/build/config.go5
-rw-r--r--ui/build/dumpvars.go10
-rw-r--r--ui/build/ninja.go21
-rw-r--r--ui/build/path.go18
-rw-r--r--ui/build/rbe.go4
-rw-r--r--ui/build/soong.go10
153 files changed, 5191 insertions, 2070 deletions
diff --git a/OWNERS b/OWNERS
index e18eea173..964e27a31 100644
--- a/OWNERS
+++ b/OWNERS
@@ -4,7 +4,6 @@
# AMER
agespino@google.com
alexmarquez@google.com
-asmundak@google.com
ccross@android.com
colefaust@google.com
cparsons@google.com
@@ -27,6 +26,4 @@ yudiliu@google.com
jingwen@google.com
# EMEA
-hansson@google.com #{LAST_RESORT_SUGGESTION}
lberki@google.com
-paulduffin@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 1353293f2..89c2d195b 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -143,7 +143,10 @@ var (
"external/javassist": Bp2BuildDefaultTrueRecursively,
"external/jemalloc_new": Bp2BuildDefaultTrueRecursively,
"external/jsoncpp": Bp2BuildDefaultTrueRecursively,
+ "external/jsr305": Bp2BuildDefaultTrueRecursively,
+ "external/jsr330": Bp2BuildDefaultTrueRecursively,
"external/junit": Bp2BuildDefaultTrueRecursively,
+ "external/kotlinc": Bp2BuildDefaultTrueRecursively,
"external/libaom": Bp2BuildDefaultTrueRecursively,
"external/libavc": Bp2BuildDefaultTrueRecursively,
"external/libcap": Bp2BuildDefaultTrueRecursively,
@@ -196,6 +199,7 @@ var (
"frameworks/base/tests/appwidgets/AppWidgetHostTest": Bp2BuildDefaultTrueRecursively,
"frameworks/base/tools/aapt2": Bp2BuildDefaultTrue,
"frameworks/base/tools/streaming_proto": Bp2BuildDefaultTrueRecursively,
+ "frameworks/hardware/interfaces/stats/aidl": Bp2BuildDefaultTrue,
"frameworks/native/libs/adbd_auth": Bp2BuildDefaultTrueRecursively,
"frameworks/native/libs/arect": Bp2BuildDefaultTrueRecursively,
"frameworks/native/libs/gui": Bp2BuildDefaultTrue,
@@ -254,29 +258,32 @@ var (
"libnativehelper": Bp2BuildDefaultTrueRecursively,
- "packages/apps/DevCamera": Bp2BuildDefaultTrue,
- "packages/apps/HTMLViewer": Bp2BuildDefaultTrue,
- "packages/apps/Protips": Bp2BuildDefaultTrue,
- "packages/apps/SafetyRegulatoryInfo": Bp2BuildDefaultTrue,
- "packages/apps/WallpaperPicker": Bp2BuildDefaultTrue,
- "packages/modules/NeuralNetworks/driver/cache": Bp2BuildDefaultTrueRecursively,
- "packages/modules/StatsD/lib/libstatssocket": Bp2BuildDefaultTrueRecursively,
- "packages/modules/adb": Bp2BuildDefaultTrue,
- "packages/modules/adb/apex": Bp2BuildDefaultTrue,
- "packages/modules/adb/crypto": Bp2BuildDefaultTrueRecursively,
- "packages/modules/adb/libs": Bp2BuildDefaultTrueRecursively,
- "packages/modules/adb/pairing_auth": Bp2BuildDefaultTrueRecursively,
- "packages/modules/adb/pairing_connection": Bp2BuildDefaultTrueRecursively,
- "packages/modules/adb/proto": Bp2BuildDefaultTrueRecursively,
- "packages/modules/adb/tls": Bp2BuildDefaultTrueRecursively,
- "packages/providers/MediaProvider/tools/dialogs": Bp2BuildDefaultFalse, // TODO(b/242834374)
- "packages/screensavers/Basic": Bp2BuildDefaultTrue,
- "packages/services/Car/tests/SampleRearViewCamera": Bp2BuildDefaultFalse, // TODO(b/242834321)
+ "packages/apps/DevCamera": Bp2BuildDefaultTrue,
+ "packages/apps/HTMLViewer": Bp2BuildDefaultTrue,
+ "packages/apps/Protips": Bp2BuildDefaultTrue,
+ "packages/apps/SafetyRegulatoryInfo": Bp2BuildDefaultTrue,
+ "packages/apps/WallpaperPicker": Bp2BuildDefaultTrue,
+ "packages/modules/NeuralNetworks/driver/cache": Bp2BuildDefaultTrueRecursively,
+ "packages/modules/StatsD/lib/libstatssocket": Bp2BuildDefaultTrueRecursively,
+ "packages/modules/adb": Bp2BuildDefaultTrue,
+ "packages/modules/adb/apex": Bp2BuildDefaultTrue,
+ "packages/modules/adb/crypto": Bp2BuildDefaultTrueRecursively,
+ "packages/modules/adb/libs": Bp2BuildDefaultTrueRecursively,
+ "packages/modules/adb/pairing_auth": Bp2BuildDefaultTrueRecursively,
+ "packages/modules/adb/pairing_connection": Bp2BuildDefaultTrueRecursively,
+ "packages/modules/adb/proto": Bp2BuildDefaultTrueRecursively,
+ "packages/modules/adb/tls": Bp2BuildDefaultTrueRecursively,
+ "packages/modules/NetworkStack/common/captiveportal": Bp2BuildDefaultTrue,
+ "packages/providers/MediaProvider/tools/dialogs": Bp2BuildDefaultFalse, // TODO(b/242834374)
+ "packages/screensavers/Basic": Bp2BuildDefaultTrue,
+ "packages/services/Car/tests/SampleRearViewCamera": Bp2BuildDefaultFalse, // TODO(b/242834321)
"platform_testing/tests/example": Bp2BuildDefaultTrueRecursively,
"prebuilts/clang/host/linux-x86": Bp2BuildDefaultTrueRecursively,
+ "prebuilts/gradle-plugin": Bp2BuildDefaultTrueRecursively,
"prebuilts/runtime/mainline/platform/sdk": Bp2BuildDefaultTrueRecursively,
+ "prebuilts/sdk/current/androidx": Bp2BuildDefaultTrue,
"prebuilts/sdk/current/extras/app-toolkit": Bp2BuildDefaultTrue,
"prebuilts/sdk/current/support": Bp2BuildDefaultTrue,
"prebuilts/tools": Bp2BuildDefaultTrue,
@@ -345,7 +352,8 @@ var (
"system/tools/sysprop": Bp2BuildDefaultTrue,
"system/unwinding/libunwindstack": Bp2BuildDefaultTrueRecursively,
- "tools/apksig": Bp2BuildDefaultTrue,
+ "tools/apksig": Bp2BuildDefaultTrue,
+ "tools/metalava": Bp2BuildDefaultTrue,
"tools/platform-compat/java/android/compat": Bp2BuildDefaultTrueRecursively,
"tools/tradefederation/prebuilts/filegroups": Bp2BuildDefaultTrueRecursively,
}
@@ -369,7 +377,6 @@ var (
"external/bazelbuild-kotlin-rules":/* recursive = */ true,
"external/bazel-skylib":/* recursive = */ true,
"external/guava":/* recursive = */ true,
- "external/jsr305":/* recursive = */ true,
"external/protobuf":/* recursive = */ false,
"external/python/absl-py":/* recursive = */ true,
@@ -379,8 +386,8 @@ var (
"frameworks/base/tools/codegen":/* recursive = */ true,
"frameworks/ex/common":/* recursive = */ true,
+ // Building manually due to b/179889880: resource files cross package boundary
"packages/apps/Music":/* recursive = */ true,
- "packages/apps/QuickSearchBox":/* recursive = */ true,
"prebuilts/abi-dumps/platform":/* recursive = */ true,
"prebuilts/abi-dumps/ndk":/* recursive = */ true,
@@ -679,16 +686,20 @@ var (
// kotlin srcs in android_library
"renderscript_toolkit",
+
+ //kotlin srcs in android_binary
+ "MusicKotlin",
}
Bp2buildModuleTypeAlwaysConvertList = []string{
"aidl_interface_headers",
+ "bpf",
"license",
"linker_config",
"java_import",
"java_import_host",
+ "java_sdk_library",
"sysprop_library",
- "bpf",
}
// Add the names of modules that bp2build should never convert, if it is
@@ -1326,6 +1337,9 @@ var (
// uses glob in $(locations)
"libc_musl_sysroot",
+
+ // TODO(b/266459895): depends on libunwindstack
+ "libutils_test",
}
MixedBuildsDisabledList = []string{
@@ -1401,6 +1415,13 @@ var (
ProdMixedBuildsEnabledList = []string{
"com.android.tzdata",
"test1_com.android.tzdata",
+ "com.android.adbd",
+ "test_com.android.adbd",
+ "adbd_test",
+ "adb_crypto_test",
+ "adb_pairing_auth_test",
+ "adb_pairing_connection_test",
+ "adb_tls_connection_test",
}
// Staging-mode allowlist. Modules in this list are only built
@@ -1408,12 +1429,21 @@ var (
// which will soon be added to the prod allowlist.
// It is implicit that all modules in ProdMixedBuildsEnabledList will
// also be built - do not add them to this list.
- StagingMixedBuildsEnabledList = []string{
- "com.android.adbd",
- "adbd_test",
- "adb_crypto_test",
- "adb_pairing_auth_test",
- "adb_pairing_connection_test",
- "adb_tls_connection_test",
+ StagingMixedBuildsEnabledList = []string{}
+
+ // These should be the libs that are included by the apexes in the ProdMixedBuildsEnabledList
+ ProdDclaMixedBuildsEnabledList = []string{}
+
+ // These should be the libs that are included by the apexes in the StagingMixedBuildsEnabledList
+ StagingDclaMixedBuildsEnabledList = []string{
+ "libbase",
+ "libc++",
+ "libcrypto",
+ "libcutils",
}
+
+ // TODO(b/269342245): Enable the rest of the DCLA libs
+ // "libssl",
+ // "libstagefright_flacdec",
+ // "libutils",
)
diff --git a/android/androidmk.go b/android/androidmk.go
index 6346401c7..14b2e8237 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -501,6 +501,7 @@ func (a *AndroidMkEntries) WriteLicenseVariables(w io.Writer) {
// generate and fill in AndroidMkEntries's in-struct data, ready to be flushed to a file.
type fillInEntriesContext interface {
ModuleDir(module blueprint.Module) string
+ ModuleSubDir(module blueprint.Module) string
Config() Config
ModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{}
ModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool
@@ -528,7 +529,7 @@ func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint
fmt.Fprintf(&a.header, distString)
}
- fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS) # "+ctx.ModuleType(mod))
+ fmt.Fprintf(&a.header, "\ninclude $(CLEAR_VARS) # type: %s, name: %s, variant: %s\n", ctx.ModuleType(mod), base.BaseModuleName(), ctx.ModuleSubDir(mod))
// Collect make variable assignment entries.
a.SetString("LOCAL_PATH", ctx.ModuleDir(mod))
diff --git a/android/apex.go b/android/apex.go
index 3c945ae6a..358818f47 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -817,7 +817,7 @@ func (d *ApexBundleDepsInfo) BuildDepsInfoLists(ctx ModuleContext, minSdkVersion
var flatContent strings.Builder
fmt.Fprintf(&fullContent, "%s(minSdkVersion:%s):\n", ctx.ModuleName(), minSdkVersion)
- for _, key := range FirstUniqueStrings(SortedStringKeys(depInfos)) {
+ for _, key := range FirstUniqueStrings(SortedKeys(depInfos)) {
info := depInfos[key]
toName := fmt.Sprintf("%s(minSdkVersion:%s)", info.To, info.MinSdkVersion)
if info.IsExternal {
diff --git a/android/api_levels.go b/android/api_levels.go
index bf7b31736..6d7552ff7 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -302,31 +302,35 @@ func GetApiLevelsJson(ctx PathContext) WritablePath {
return PathForOutput(ctx, "api_levels.json")
}
+func getApiLevelsMapReleasedVersions() map[string]int {
+ return map[string]int{
+ "G": 9,
+ "I": 14,
+ "J": 16,
+ "J-MR1": 17,
+ "J-MR2": 18,
+ "K": 19,
+ "L": 21,
+ "L-MR1": 22,
+ "M": 23,
+ "N": 24,
+ "N-MR1": 25,
+ "O": 26,
+ "O-MR1": 27,
+ "P": 28,
+ "Q": 29,
+ "R": 30,
+ "S": 31,
+ "S-V2": 32,
+ "Tiramisu": 33,
+ }
+}
+
var finalCodenamesMapKey = NewOnceKey("FinalCodenamesMap")
func getFinalCodenamesMap(config Config) map[string]int {
return config.Once(finalCodenamesMapKey, func() interface{} {
- apiLevelsMap := map[string]int{
- "G": 9,
- "I": 14,
- "J": 16,
- "J-MR1": 17,
- "J-MR2": 18,
- "K": 19,
- "L": 21,
- "L-MR1": 22,
- "M": 23,
- "N": 24,
- "N-MR1": 25,
- "O": 26,
- "O-MR1": 27,
- "P": 28,
- "Q": 29,
- "R": 30,
- "S": 31,
- "S-V2": 32,
- "Tiramisu": 33,
- }
+ apiLevelsMap := getApiLevelsMapReleasedVersions()
// TODO: Differentiate "current" and "future".
// The code base calls it FutureApiLevel, but the spelling is "current",
@@ -349,29 +353,10 @@ func getFinalCodenamesMap(config Config) map[string]int {
var apiLevelsMapKey = NewOnceKey("ApiLevelsMap")
+// ApiLevelsMap has entries for preview API levels
func GetApiLevelsMap(config Config) map[string]int {
return config.Once(apiLevelsMapKey, func() interface{} {
- apiLevelsMap := map[string]int{
- "G": 9,
- "I": 14,
- "J": 16,
- "J-MR1": 17,
- "J-MR2": 18,
- "K": 19,
- "L": 21,
- "L-MR1": 22,
- "M": 23,
- "N": 24,
- "N-MR1": 25,
- "O": 26,
- "O-MR1": 27,
- "P": 28,
- "Q": 29,
- "R": 30,
- "S": 31,
- "S-V2": 32,
- "Tiramisu": 33,
- }
+ apiLevelsMap := getApiLevelsMapReleasedVersions()
for i, codename := range config.PlatformVersionActiveCodenames() {
apiLevelsMap[codename] = previewAPILevelBase + i
}
@@ -386,20 +371,11 @@ func (a *apiLevelsSingleton) GenerateBuildActions(ctx SingletonContext) {
createApiLevelsJson(ctx, apiLevelsJson, apiLevelsMap)
}
-func printApiLevelsStarlarkDict(config Config) string {
- apiLevelsMap := GetApiLevelsMap(config)
- valDict := make(map[string]string, len(apiLevelsMap))
- for k, v := range apiLevelsMap {
- valDict[k] = strconv.Itoa(v)
- }
- return starlark_fmt.PrintDict(valDict, 0)
-}
-
func StarlarkApiLevelConfigs(config Config) string {
return fmt.Sprintf(bazel.GeneratedBazelFileWarning+`
-_api_levels = %s
+_api_levels_released_versions = %s
-api_levels = _api_levels
-`, printApiLevelsStarlarkDict(config),
+api_levels_released_versions = _api_levels_released_versions
+`, starlark_fmt.PrintStringIntDict(getApiLevelsMapReleasedVersions(), 0),
)
}
diff --git a/android/bazel.go b/android/bazel.go
index 10e925154..b60075840 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -352,11 +352,13 @@ func GetBp2BuildAllowList() Bp2BuildConversionAllowlist {
// metrics reporting.
func MixedBuildsEnabled(ctx BaseModuleContext) bool {
module := ctx.Module()
+ apexInfo := ctx.Provider(ApexInfoProvider).(ApexInfo)
+ withinApex := !apexInfo.IsForPlatform()
mixedBuildEnabled := ctx.Config().IsMixedBuildsEnabled() &&
ctx.Os() != Windows && // Windows toolchains are not currently supported.
module.Enabled() &&
convertedToBazel(ctx, module) &&
- ctx.Config().BazelContext.IsModuleNameAllowed(module.Name())
+ ctx.Config().BazelContext.IsModuleNameAllowed(module.Name(), withinApex)
ctx.Config().LogMixedBuild(ctx, mixedBuildEnabled)
return mixedBuildEnabled
}
@@ -526,3 +528,15 @@ func GetMainClassInManifest(c Config, filepath string) (string, error) {
return "", errors.New("Main-Class is not found.")
}
+
+func AttachValidationActions(ctx ModuleContext, outputFilePath Path, validations Paths) ModuleOutPath {
+ validatedOutputFilePath := PathForModuleOut(ctx, "validated", outputFilePath.Base())
+ ctx.Build(pctx, BuildParams{
+ Rule: CpNoPreserveSymlink,
+ Description: "run validations " + outputFilePath.Base(),
+ Output: validatedOutputFilePath,
+ Input: outputFilePath,
+ Validations: validations,
+ })
+ return validatedOutputFilePath
+}
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index ac4ced85d..e7b84e304 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -29,8 +29,10 @@ import (
"android/soong/android/allowlists"
"android/soong/bazel/cquery"
"android/soong/shared"
+ "android/soong/starlark_fmt"
"github.com/google/blueprint"
+ "github.com/google/blueprint/metrics"
"android/soong/bazel"
)
@@ -43,6 +45,30 @@ var (
Description: "",
CommandDeps: []string{"${bazelBuildRunfilesTool}"},
}, "outDir")
+ allowedBazelEnvironmentVars = []string{
+ // clang-tidy
+ "ALLOW_LOCAL_TIDY_TRUE",
+ "DEFAULT_TIDY_HEADER_DIRS",
+ "TIDY_TIMEOUT",
+ "WITH_TIDY",
+ "WITH_TIDY_FLAGS",
+ "TIDY_EXTERNAL_VENDOR",
+
+ "SKIP_ABI_CHECKS",
+ "UNSAFE_DISABLE_APEX_ALLOWED_DEPS_CHECK",
+ "AUTO_ZERO_INITIALIZE",
+ "AUTO_PATTERN_INITIALIZE",
+ "AUTO_UNINITIALIZE",
+ "USE_CCACHE",
+ "LLVM_NEXT",
+ "ALLOW_UNKNOWN_WARNING_OPTION",
+
+ // Overrides the version in the apex_manifest.json. The version is unique for
+ // each branch (internal, aosp, mainline releases, dessert releases). This
+ // enables modules built on an older branch to be installed against a newer
+ // device for development purposes.
+ "OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION",
+ }
)
func init() {
@@ -83,12 +109,29 @@ type cqueryRequest interface {
// Portion of cquery map key to describe target configuration.
type configKey struct {
- arch string
- osType OsType
+ arch string
+ osType OsType
+ apexKey ApexConfigKey
+}
+
+type ApexConfigKey struct {
+ WithinApex bool
+ ApexSdkVersion string
+}
+
+func (c ApexConfigKey) String() string {
+ return fmt.Sprintf("%s_%s", withinApexToString(c.WithinApex), c.ApexSdkVersion)
+}
+
+func withinApexToString(withinApex bool) string {
+ if withinApex {
+ return "within_apex"
+ }
+ return ""
}
func (c configKey) String() string {
- return fmt.Sprintf("%s::%s", c.arch, c.osType)
+ return fmt.Sprintf("%s::%s::%s", c.arch, c.osType, c.apexKey)
}
// Map key to describe bazel cquery requests.
@@ -110,6 +153,10 @@ func (c cqueryKey) String() string {
return fmt.Sprintf("cquery(%s,%s,%s)", c.label, c.requestType.Name(), c.configKey)
}
+type invokeBazelContext interface {
+ GetEventHandler() *metrics.EventHandler
+}
+
// BazelContext is a context object useful for interacting with Bazel during
// the course of a build. Use of Bazel to evaluate part of the build graph
// is referred to as a "mixed build". (Some modules are managed by Soong,
@@ -146,27 +193,29 @@ type BazelContext interface {
// Issues commands to Bazel to receive results for all cquery requests
// queued in the BazelContext. The ctx argument is optional and is only
// used for performance data collection
- InvokeBazel(config Config, ctx *Context) error
+ InvokeBazel(config Config, ctx invokeBazelContext) error
// Returns true if Bazel handling is enabled for the module with the given name.
// Note that this only implies "bazel mixed build" allowlisting. The caller
// should independently verify the module is eligible for Bazel handling
// (for example, that it is MixedBuildBuildable).
- IsModuleNameAllowed(moduleName string) bool
+ IsModuleNameAllowed(moduleName string, withinApex bool) bool
+
+ IsModuleDclaAllowed(moduleName string) bool
// Returns the bazel output base (the root directory for all bazel intermediate outputs).
OutputBase() string
// Returns build statements which should get registered to reflect Bazel's outputs.
- BuildStatementsToRegister() []bazel.BuildStatement
+ BuildStatementsToRegister() []*bazel.BuildStatement
// Returns the depsets defined in Bazel's aquery response.
AqueryDepsets() []bazel.AqueryDepset
}
type bazelRunner interface {
- createBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) *exec.Cmd
- issueBazelCommand(bazelCmd *exec.Cmd) (output string, errorMessage string, error error)
+ createBazelCommand(config Config, paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) *exec.Cmd
+ issueBazelCommand(bazelCmd *exec.Cmd, eventHandler *metrics.EventHandler) (output string, errorMessage string, error error)
}
type bazelPaths struct {
@@ -183,14 +232,16 @@ type bazelPaths struct {
// and their results after the requests have been made.
type mixedBuildBazelContext struct {
bazelRunner
- paths *bazelPaths
- requests map[cqueryKey]bool // cquery requests that have not yet been issued to Bazel
- requestMutex sync.Mutex // requests can be written in parallel
+ paths *bazelPaths
+ // cquery requests that have not yet been issued to Bazel. This list is maintained
+ // in a sorted state, and is guaranteed to have no duplicates.
+ requests []cqueryKey
+ requestMutex sync.Mutex // requests can be written in parallel
results map[cqueryKey]string // Results of cquery requests after Bazel invocations
// Build statements which should get registered to reflect Bazel's outputs.
- buildStatements []bazel.BuildStatement
+ buildStatements []*bazel.BuildStatement
// Depsets which should be used for Bazel's build statements.
depsets []bazel.AqueryDepset
@@ -203,6 +254,8 @@ type mixedBuildBazelContext struct {
bazelDisabledModules map[string]bool
// Per-module allowlist to opt modules in to bazel handling.
bazelEnabledModules map[string]bool
+ // DCLA modules are enabled when used in apex.
+ bazelDclaEnabledModules map[string]bool
// If true, modules are bazel-enabled by default, unless present in bazelDisabledModules.
modulesDefaultToBazel bool
@@ -226,10 +279,16 @@ type MockBazelContext struct {
LabelToPythonBinary map[string]string
LabelToApexInfo map[string]cquery.ApexInfo
LabelToCcBinary map[string]cquery.CcUnstrippedInfo
+
+ BazelRequests map[string]bool
}
-func (m MockBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
- panic("unimplemented")
+func (m MockBazelContext) QueueBazelRequest(label string, requestType cqueryRequest, cfgKey configKey) {
+ key := BuildMockBazelContextRequestKey(label, requestType, cfgKey.arch, cfgKey.osType, cfgKey.apexKey)
+ if m.BazelRequests == nil {
+ m.BazelRequests = make(map[string]bool)
+ }
+ m.BazelRequests[key] = true
}
func (m MockBazelContext) GetOutputFiles(label string, _ configKey) ([]string, error) {
@@ -240,10 +299,14 @@ func (m MockBazelContext) GetOutputFiles(label string, _ configKey) ([]string, e
return result, nil
}
-func (m MockBazelContext) GetCcInfo(label string, _ configKey) (cquery.CcInfo, error) {
+func (m MockBazelContext) GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, error) {
result, ok := m.LabelToCcInfo[label]
if !ok {
- return cquery.CcInfo{}, fmt.Errorf("no target with label %q in LabelToCcInfo", label)
+ key := BuildMockBazelContextResultKey(label, cfgKey.arch, cfgKey.osType, cfgKey.apexKey)
+ result, ok = m.LabelToCcInfo[key]
+ if !ok {
+ return cquery.CcInfo{}, fmt.Errorf("no target with label %q in LabelToCcInfo", label)
+ }
}
return result, nil
}
@@ -272,18 +335,22 @@ func (m MockBazelContext) GetCcUnstrippedInfo(label string, _ configKey) (cquery
return result, nil
}
-func (m MockBazelContext) InvokeBazel(_ Config, _ *Context) error {
+func (m MockBazelContext) InvokeBazel(_ Config, _ invokeBazelContext) error {
panic("unimplemented")
}
-func (m MockBazelContext) IsModuleNameAllowed(_ string) bool {
+func (m MockBazelContext) IsModuleNameAllowed(_ string, _ bool) bool {
+ return true
+}
+
+func (m MockBazelContext) IsModuleDclaAllowed(_ string) bool {
return true
}
func (m MockBazelContext) OutputBase() string { return m.OutputBaseDir }
-func (m MockBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
- return []bazel.BuildStatement{}
+func (m MockBazelContext) BuildStatementsToRegister() []*bazel.BuildStatement {
+ return []*bazel.BuildStatement{}
}
func (m MockBazelContext) AqueryDepsets() []bazel.AqueryDepset {
@@ -292,11 +359,53 @@ func (m MockBazelContext) AqueryDepsets() []bazel.AqueryDepset {
var _ BazelContext = MockBazelContext{}
+func BuildMockBazelContextRequestKey(label string, request cqueryRequest, arch string, osType OsType, apexKey ApexConfigKey) string {
+ cfgKey := configKey{
+ arch: arch,
+ osType: osType,
+ apexKey: apexKey,
+ }
+
+ return strings.Join([]string{label, request.Name(), cfgKey.String()}, "_")
+}
+
+func BuildMockBazelContextResultKey(label string, arch string, osType OsType, apexKey ApexConfigKey) string {
+ cfgKey := configKey{
+ arch: arch,
+ osType: osType,
+ apexKey: apexKey,
+ }
+
+ return strings.Join([]string{label, cfgKey.String()}, "_")
+}
+
func (bazelCtx *mixedBuildBazelContext) QueueBazelRequest(label string, requestType cqueryRequest, cfgKey configKey) {
key := makeCqueryKey(label, requestType, cfgKey)
bazelCtx.requestMutex.Lock()
defer bazelCtx.requestMutex.Unlock()
- bazelCtx.requests[key] = true
+
+ // Insert key into requests, maintaining the sort, and only if it's not duplicate.
+ keyString := key.String()
+ foundEqual := false
+ notLessThanKeyString := func(i int) bool {
+ s := bazelCtx.requests[i].String()
+ v := strings.Compare(s, keyString)
+ if v == 0 {
+ foundEqual = true
+ }
+ return v >= 0
+ }
+ targetIndex := sort.Search(len(bazelCtx.requests), notLessThanKeyString)
+ if foundEqual {
+ return
+ }
+
+ if targetIndex == len(bazelCtx.requests) {
+ bazelCtx.requests = append(bazelCtx.requests, key)
+ } else {
+ bazelCtx.requests = append(bazelCtx.requests[:targetIndex+1], bazelCtx.requests[targetIndex:]...)
+ bazelCtx.requests[targetIndex] = key
+ }
}
func (bazelCtx *mixedBuildBazelContext) GetOutputFiles(label string, cfgKey configKey) ([]string, error) {
@@ -368,7 +477,7 @@ func (n noopBazelContext) GetCcUnstrippedInfo(_ string, _ configKey) (cquery.CcU
panic("implement me")
}
-func (n noopBazelContext) InvokeBazel(_ Config, _ *Context) error {
+func (n noopBazelContext) InvokeBazel(_ Config, _ invokeBazelContext) error {
panic("unimplemented")
}
@@ -376,26 +485,31 @@ func (m noopBazelContext) OutputBase() string {
return ""
}
-func (n noopBazelContext) IsModuleNameAllowed(_ string) bool {
+func (n noopBazelContext) IsModuleNameAllowed(_ string, _ bool) bool {
+ return false
+}
+
+func (n noopBazelContext) IsModuleDclaAllowed(_ string) bool {
return false
}
-func (m noopBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
- return []bazel.BuildStatement{}
+func (m noopBazelContext) BuildStatementsToRegister() []*bazel.BuildStatement {
+ return []*bazel.BuildStatement{}
}
func (m noopBazelContext) AqueryDepsets() []bazel.AqueryDepset {
return []bazel.AqueryDepset{}
}
+func addToStringSet(set map[string]bool, items []string) {
+ for _, item := range items {
+ set[item] = true
+ }
+}
+
func GetBazelEnabledAndDisabledModules(buildMode SoongBuildMode, forceEnabled map[string]struct{}) (map[string]bool, map[string]bool) {
disabledModules := map[string]bool{}
enabledModules := map[string]bool{}
- addToStringSet := func(set map[string]bool, items []string) {
- for _, item := range items {
- set[item] = true
- }
- }
switch buildMode {
case BazelProdMode:
@@ -483,16 +597,24 @@ func NewBazelContext(c *config) (BazelContext, error) {
if c.HasDeviceProduct() {
targetProduct = c.DeviceProduct()
}
-
+ dclaMixedBuildsEnabledList := []string{}
+ if c.BuildMode == BazelProdMode {
+ dclaMixedBuildsEnabledList = allowlists.ProdDclaMixedBuildsEnabledList
+ } else if c.BuildMode == BazelStagingMode {
+ dclaMixedBuildsEnabledList = append(allowlists.ProdDclaMixedBuildsEnabledList,
+ allowlists.StagingDclaMixedBuildsEnabledList...)
+ }
+ dclaEnabledModules := map[string]bool{}
+ addToStringSet(dclaEnabledModules, dclaMixedBuildsEnabledList)
return &mixedBuildBazelContext{
- bazelRunner: &builtinBazelRunner{},
- paths: &paths,
- requests: make(map[cqueryKey]bool),
- modulesDefaultToBazel: c.BuildMode == BazelDevMode,
- bazelEnabledModules: enabledModules,
- bazelDisabledModules: disabledModules,
- targetProduct: targetProduct,
- targetBuildVariant: targetBuildVariant,
+ bazelRunner: &builtinBazelRunner{c.UseBazelProxy, absolutePath(c.outDir)},
+ paths: &paths,
+ modulesDefaultToBazel: c.BuildMode == BazelDevMode,
+ bazelEnabledModules: enabledModules,
+ bazelDisabledModules: disabledModules,
+ bazelDclaEnabledModules: dclaEnabledModules,
+ targetProduct: targetProduct,
+ targetBuildVariant: targetBuildVariant,
}, nil
}
@@ -500,16 +622,24 @@ func (p *bazelPaths) BazelMetricsDir() string {
return p.metricsDir
}
-func (context *mixedBuildBazelContext) IsModuleNameAllowed(moduleName string) bool {
+func (context *mixedBuildBazelContext) IsModuleNameAllowed(moduleName string, withinApex bool) bool {
if context.bazelDisabledModules[moduleName] {
return false
}
if context.bazelEnabledModules[moduleName] {
return true
}
+ if withinApex && context.IsModuleDclaAllowed(moduleName) {
+ return true
+ }
+
return context.modulesDefaultToBazel
}
+func (context *mixedBuildBazelContext) IsModuleDclaAllowed(moduleName string) bool {
+ return context.bazelDclaEnabledModules[moduleName]
+}
+
func pwdPrefix() string {
// Darwin doesn't have /proc
if runtime.GOOS != "darwin" {
@@ -535,7 +665,7 @@ type mockBazelRunner struct {
extraFlags []string
}
-func (r *mockBazelRunner) createBazelCommand(_ *bazelPaths, _ bazel.RunName,
+func (r *mockBazelRunner) createBazelCommand(_ Config, _ *bazelPaths, _ bazel.RunName,
command bazelCommand, extraFlags ...string) *exec.Cmd {
r.commands = append(r.commands, command)
r.extraFlags = append(r.extraFlags, strings.Join(extraFlags, " "))
@@ -547,32 +677,57 @@ func (r *mockBazelRunner) createBazelCommand(_ *bazelPaths, _ bazel.RunName,
return cmd
}
-func (r *mockBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd) (string, string, error) {
+func (r *mockBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd, _ *metrics.EventHandler) (string, string, error) {
if command, ok := r.tokens[bazelCmd]; ok {
return r.bazelCommandResults[command], "", nil
}
return "", "", nil
}
-type builtinBazelRunner struct{}
+type builtinBazelRunner struct {
+ useBazelProxy bool
+ outDir string
+}
// Issues the given bazel command with given build label and additional flags.
// Returns (stdout, stderr, error). The first and second return values are strings
// containing the stdout and stderr of the run command, and an error is returned if
// the invocation returned an error code.
-func (r *builtinBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd) (string, string, error) {
- stderr := &bytes.Buffer{}
- bazelCmd.Stderr = stderr
- if output, err := bazelCmd.Output(); err != nil {
- return "", string(stderr.Bytes()),
- fmt.Errorf("bazel command failed: %s\n---command---\n%s\n---env---\n%s\n---stderr---\n%s---",
- err, bazelCmd, strings.Join(bazelCmd.Env, "\n"), stderr)
+func (r *builtinBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd, eventHandler *metrics.EventHandler) (string, string, error) {
+ if r.useBazelProxy {
+ eventHandler.Begin("client_proxy")
+ defer eventHandler.End("client_proxy")
+ proxyClient := bazel.NewProxyClient(r.outDir)
+ // Omit the arg containing the Bazel binary, as that is handled by the proxy
+ // server.
+ bazelFlags := bazelCmd.Args[1:]
+ // TODO(b/270989498): Refactor these functions to not take exec.Cmd, as its
+ // not actually executed for client proxying.
+ resp, err := proxyClient.IssueCommand(bazel.CmdRequest{bazelFlags, bazelCmd.Env})
+
+ if err != nil {
+ return "", "", err
+ }
+ if len(resp.ErrorString) > 0 {
+ return "", "", fmt.Errorf(resp.ErrorString)
+ }
+ return resp.Stdout, resp.Stderr, nil
} else {
- return string(output), string(stderr.Bytes()), nil
+ eventHandler.Begin("bazel command")
+ defer eventHandler.End("bazel command")
+ stderr := &bytes.Buffer{}
+ bazelCmd.Stderr = stderr
+ if output, err := bazelCmd.Output(); err != nil {
+ return "", string(stderr.Bytes()),
+ fmt.Errorf("bazel command failed: %s\n---command---\n%s\n---env---\n%s\n---stderr---\n%s---",
+ err, bazelCmd, strings.Join(bazelCmd.Env, "\n"), stderr)
+ } else {
+ return string(output), string(stderr.Bytes()), nil
+ }
}
}
-func (r *builtinBazelRunner) createBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand,
+func (r *builtinBazelRunner) createBazelCommand(config Config, paths *bazelPaths, runName bazel.RunName, command bazelCommand,
extraFlags ...string) *exec.Cmd {
cmdFlags := []string{
"--output_base=" + absolutePath(paths.outputBase),
@@ -616,6 +771,13 @@ func (r *builtinBazelRunner) createBazelCommand(paths *bazelPaths, runName bazel
// explicitly in BUILD files.
"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1",
}
+ for _, envvar := range allowedBazelEnvironmentVars {
+ val := config.Getenv(envvar)
+ if val == "" {
+ continue
+ }
+ extraEnv = append(extraEnv, fmt.Sprintf("%s=%s", envvar, val))
+ }
bazelCmd.Env = append(os.Environ(), extraEnv...)
return bazelCmd
@@ -634,21 +796,37 @@ func (context *mixedBuildBazelContext) mainBzlFileContents() []byte {
#####################################################
# This file is generated by soong_build. Do not edit.
#####################################################
-
def _config_node_transition_impl(settings, attr):
if attr.os == "android" and attr.arch == "target":
target = "{PRODUCT}-{VARIANT}"
else:
target = "{PRODUCT}-{VARIANT}_%s_%s" % (attr.os, attr.arch)
- return {
+ apex_name = ""
+ if attr.within_apex:
+ # //build/bazel/rules/apex:apex_name has to be set to a non_empty value,
+ # otherwise //build/bazel/rules/apex:non_apex will be true and the
+ # "-D__ANDROID_APEX__" compiler flag will be missing. Apex_name is used
+ # in some validation on bazel side which don't really apply in mixed
+ # build because soong will do the work, so we just set it to a fixed
+ # value here.
+ apex_name = "dcla_apex"
+ outputs = {
"//command_line_option:platforms": "@soong_injection//product_config_platforms/products/{PRODUCT}-{VARIANT}:%s" % target,
+ "@//build/bazel/rules/apex:within_apex": attr.within_apex,
+ "@//build/bazel/rules/apex:min_sdk_version": attr.apex_sdk_version,
+ "@//build/bazel/rules/apex:apex_name": apex_name,
}
+ return outputs
+
_config_node_transition = transition(
implementation = _config_node_transition_impl,
inputs = [],
outputs = [
"//command_line_option:platforms",
+ "@//build/bazel/rules/apex:within_apex",
+ "@//build/bazel/rules/apex:min_sdk_version",
+ "@//build/bazel/rules/apex:apex_name",
],
)
@@ -658,9 +836,11 @@ def _passthrough_rule_impl(ctx):
config_node = rule(
implementation = _passthrough_rule_impl,
attrs = {
- "arch" : attr.string(mandatory = True),
- "os" : attr.string(mandatory = True),
- "deps" : attr.label_list(cfg = _config_node_transition, allow_files = True),
+ "arch" : attr.string(mandatory = True),
+ "os" : attr.string(mandatory = True),
+ "within_apex" : attr.bool(default = False),
+ "apex_sdk_version" : attr.string(mandatory = True),
+ "deps" : attr.label_list(cfg = _config_node_transition, allow_files = True),
"_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"),
},
)
@@ -719,6 +899,8 @@ phony_root(name = "phonyroot",
config_node(name = "%s",
arch = "%s",
os = "%s",
+ within_apex = %s,
+ apex_sdk_version = "%s",
deps = [%s],
testonly = True, # Unblocks testonly deps.
)
@@ -727,24 +909,46 @@ config_node(name = "%s",
configNodesSection := ""
labelsByConfig := map[string][]string{}
- for val := range context.requests {
+
+ for _, val := range context.requests {
labelString := fmt.Sprintf("\"@%s\"", val.label)
configString := getConfigString(val)
labelsByConfig[configString] = append(labelsByConfig[configString], labelString)
}
+ // Configs need to be sorted to maintain determinism of the BUILD file.
+ sortedConfigs := make([]string, 0, len(labelsByConfig))
+ for val := range labelsByConfig {
+ sortedConfigs = append(sortedConfigs, val)
+ }
+ sort.Slice(sortedConfigs, func(i, j int) bool { return sortedConfigs[i] < sortedConfigs[j] })
+
allLabels := []string{}
- for configString, labels := range labelsByConfig {
+ for _, configString := range sortedConfigs {
+ labels := labelsByConfig[configString]
configTokens := strings.Split(configString, "|")
- if len(configTokens) != 2 {
+ if len(configTokens) < 2 {
panic(fmt.Errorf("Unexpected config string format: %s", configString))
}
archString := configTokens[0]
osString := configTokens[1]
+ withinApex := "False"
+ apexSdkVerString := ""
targetString := fmt.Sprintf("%s_%s", osString, archString)
+ if len(configTokens) > 2 {
+ targetString += "_" + configTokens[2]
+ if configTokens[2] == withinApexToString(true) {
+ withinApex = "True"
+ }
+ }
+ if len(configTokens) > 3 {
+ targetString += "_" + configTokens[3]
+ apexSdkVerString = configTokens[3]
+ }
allLabels = append(allLabels, fmt.Sprintf("\":%s\"", targetString))
labelsString := strings.Join(labels, ",\n ")
- configNodesSection += fmt.Sprintf(configNodeFormatString, targetString, archString, osString, labelsString)
+ configNodesSection += fmt.Sprintf(configNodeFormatString, targetString, archString, osString, withinApex, apexSdkVerString,
+ labelsString)
}
return []byte(fmt.Sprintf(formatString, configNodesSection, strings.Join(allLabels, ",\n ")))
@@ -765,7 +969,7 @@ func indent(original string) string {
// request type.
func (context *mixedBuildBazelContext) cqueryStarlarkFileContents() []byte {
requestTypeToCqueryIdEntries := map[cqueryRequest][]string{}
- for val := range context.requests {
+ for _, val := range context.requests {
cqueryId := getCqueryId(val)
mapEntryString := fmt.Sprintf("%q : True", cqueryId)
requestTypeToCqueryIdEntries[val.requestType] =
@@ -840,6 +1044,7 @@ def get_arch(target):
# Soong treats filegroups, but it may not be the case with manually-written
# filegroup BUILD targets.
buildoptions = build_options(target)
+
if buildoptions == None:
# File targets do not have buildoptions. File targets aren't associated with
# any specific platform architecture in mixed builds, so use the host.
@@ -856,15 +1061,26 @@ def get_arch(target):
if not platform_name.startswith("{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}"):
fail("expected platform name of the form '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_android_<arch>' or '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str(platforms))
platform_name = platform_name.removeprefix("{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}").removeprefix("_")
+ config_key = ""
if not platform_name:
- return "target|android"
+ config_key = "target|android"
elif platform_name.startswith("android_"):
- return platform_name.removeprefix("android_") + "|android"
+ config_key = platform_name.removeprefix("android_") + "|android"
elif platform_name.startswith("linux_"):
- return platform_name.removeprefix("linux_") + "|linux"
+ config_key = platform_name.removeprefix("linux_") + "|linux"
else:
fail("expected platform name of the form '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_android_<arch>' or '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str(platforms))
+ within_apex = buildoptions.get("//build/bazel/rules/apex:within_apex")
+ apex_sdk_version = buildoptions.get("//build/bazel/rules/apex:min_sdk_version")
+
+ if within_apex:
+ config_key += "|within_apex"
+ if apex_sdk_version != None and len(apex_sdk_version) > 0:
+ config_key += "|" + apex_sdk_version
+
+ return config_key
+
def format(target):
id_string = str(target.label) + "|" + get_arch(target)
@@ -921,11 +1137,10 @@ var (
// Issues commands to Bazel to receive results for all cquery requests
// queued in the BazelContext.
-func (context *mixedBuildBazelContext) InvokeBazel(config Config, ctx *Context) error {
- if ctx != nil {
- ctx.EventHandler.Begin("bazel")
- defer ctx.EventHandler.End("bazel")
- }
+func (context *mixedBuildBazelContext) InvokeBazel(config Config, ctx invokeBazelContext) error {
+ eventHandler := ctx.GetEventHandler()
+ eventHandler.Begin("bazel")
+ defer eventHandler.End("bazel")
if metricsDir := context.paths.BazelMetricsDir(); metricsDir != "" {
if err := os.MkdirAll(metricsDir, 0777); err != nil {
@@ -933,26 +1148,25 @@ func (context *mixedBuildBazelContext) InvokeBazel(config Config, ctx *Context)
}
}
context.results = make(map[cqueryKey]string)
- if err := context.runCquery(ctx); err != nil {
+ if err := context.runCquery(config, ctx); err != nil {
return err
}
if err := context.runAquery(config, ctx); err != nil {
return err
}
- if err := context.generateBazelSymlinks(ctx); err != nil {
+ if err := context.generateBazelSymlinks(config, ctx); err != nil {
return err
}
// Clear requests.
- context.requests = map[cqueryKey]bool{}
+ context.requests = []cqueryKey{}
return nil
}
-func (context *mixedBuildBazelContext) runCquery(ctx *Context) error {
- if ctx != nil {
- ctx.EventHandler.Begin("cquery")
- defer ctx.EventHandler.End("cquery")
- }
+func (context *mixedBuildBazelContext) runCquery(config Config, ctx invokeBazelContext) error {
+ eventHandler := ctx.GetEventHandler()
+ eventHandler.Begin("cquery")
+ defer eventHandler.End("cquery")
soongInjectionPath := absolutePath(context.paths.injectedFilesDir())
mixedBuildsPath := filepath.Join(soongInjectionPath, "mixed_builds")
if _, err := os.Stat(mixedBuildsPath); os.IsNotExist(err) {
@@ -961,23 +1175,27 @@ func (context *mixedBuildBazelContext) runCquery(ctx *Context) error {
return err
}
}
- if err := os.WriteFile(filepath.Join(soongInjectionPath, "WORKSPACE.bazel"), []byte{}, 0666); err != nil {
+ if err := writeFileBytesIfChanged(filepath.Join(soongInjectionPath, "WORKSPACE.bazel"), []byte{}, 0666); err != nil {
return err
}
- if err := os.WriteFile(filepath.Join(mixedBuildsPath, "main.bzl"), context.mainBzlFileContents(), 0666); err != nil {
+ if err := writeFileBytesIfChanged(filepath.Join(mixedBuildsPath, "main.bzl"), context.mainBzlFileContents(), 0666); err != nil {
return err
}
- if err := os.WriteFile(filepath.Join(mixedBuildsPath, "BUILD.bazel"), context.mainBuildFileContents(), 0666); err != nil {
+ if err := writeFileBytesIfChanged(filepath.Join(mixedBuildsPath, "BUILD.bazel"), context.mainBuildFileContents(), 0666); err != nil {
return err
}
cqueryFileRelpath := filepath.Join(context.paths.injectedFilesDir(), "buildroot.cquery")
- if err := os.WriteFile(absolutePath(cqueryFileRelpath), context.cqueryStarlarkFileContents(), 0666); err != nil {
+ if err := writeFileBytesIfChanged(absolutePath(cqueryFileRelpath), context.cqueryStarlarkFileContents(), 0666); err != nil {
return err
}
- cqueryCommandWithFlag := context.createBazelCommand(context.paths, bazel.CqueryBuildRootRunName, cqueryCmd,
- "--output=starlark", "--starlark:file="+absolutePath(cqueryFileRelpath))
- cqueryOutput, cqueryErrorMessage, cqueryErr := context.issueBazelCommand(cqueryCommandWithFlag)
+ extraFlags := []string{"--output=starlark", "--starlark:file=" + absolutePath(cqueryFileRelpath)}
+ if Bool(config.productVariables.ClangCoverage) {
+ extraFlags = append(extraFlags, "--collect_code_coverage")
+ }
+
+ cqueryCommandWithFlag := context.createBazelCommand(config, context.paths, bazel.CqueryBuildRootRunName, cqueryCmd, extraFlags...)
+ cqueryOutput, cqueryErrorMessage, cqueryErr := context.issueBazelCommand(cqueryCommandWithFlag, eventHandler)
if cqueryErr != nil {
return cqueryErr
}
@@ -992,7 +1210,7 @@ func (context *mixedBuildBazelContext) runCquery(ctx *Context) error {
cqueryResults[splitLine[0]] = splitLine[1]
}
}
- for val := range context.requests {
+ for _, val := range context.requests {
if cqueryResult, ok := cqueryResults[getCqueryId(val)]; ok {
context.results[val] = cqueryResult
} else {
@@ -1003,11 +1221,18 @@ func (context *mixedBuildBazelContext) runCquery(ctx *Context) error {
return nil
}
-func (context *mixedBuildBazelContext) runAquery(config Config, ctx *Context) error {
- if ctx != nil {
- ctx.EventHandler.Begin("aquery")
- defer ctx.EventHandler.End("aquery")
+func writeFileBytesIfChanged(path string, contents []byte, perm os.FileMode) error {
+ oldContents, err := os.ReadFile(path)
+ if err != nil || !bytes.Equal(contents, oldContents) {
+ err = os.WriteFile(path, contents, perm)
}
+ return nil
+}
+
+func (context *mixedBuildBazelContext) runAquery(config Config, ctx invokeBazelContext) error {
+ eventHandler := ctx.GetEventHandler()
+ eventHandler.Begin("aquery")
+ defer eventHandler.End("aquery")
// Issue an aquery command to retrieve action information about the bazel build tree.
//
// Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
@@ -1032,28 +1257,27 @@ func (context *mixedBuildBazelContext) runAquery(config Config, ctx *Context) er
extraFlags = append(extraFlags, "--instrumentation_filter="+strings.Join(paths, ","))
}
}
- aqueryOutput, _, err := context.issueBazelCommand(context.createBazelCommand(context.paths, bazel.AqueryBuildRootRunName, aqueryCmd,
- extraFlags...))
+ aqueryOutput, _, err := context.issueBazelCommand(context.createBazelCommand(config, context.paths, bazel.AqueryBuildRootRunName, aqueryCmd,
+ extraFlags...), eventHandler)
if err != nil {
return err
}
- context.buildStatements, context.depsets, err = bazel.AqueryBuildStatements([]byte(aqueryOutput))
+ context.buildStatements, context.depsets, err = bazel.AqueryBuildStatements([]byte(aqueryOutput), eventHandler)
return err
}
-func (context *mixedBuildBazelContext) generateBazelSymlinks(ctx *Context) error {
- if ctx != nil {
- ctx.EventHandler.Begin("symlinks")
- defer ctx.EventHandler.End("symlinks")
- }
+func (context *mixedBuildBazelContext) generateBazelSymlinks(config Config, ctx invokeBazelContext) error {
+ eventHandler := ctx.GetEventHandler()
+ eventHandler.Begin("symlinks")
+ defer eventHandler.End("symlinks")
// Issue a build command of the phony root to generate symlink forests for dependencies of the
// Bazel build. This is necessary because aquery invocations do not generate this symlink forest,
// but some of symlinks may be required to resolve source dependencies of the build.
- _, _, err := context.issueBazelCommand(context.createBazelCommand(context.paths, bazel.BazelBuildPhonyRootRunName, buildCmd))
+ _, _, err := context.issueBazelCommand(context.createBazelCommand(config, context.paths, bazel.BazelBuildPhonyRootRunName, buildCmd), eventHandler)
return err
}
-func (context *mixedBuildBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
+func (context *mixedBuildBazelContext) BuildStatementsToRegister() []*bazel.BuildStatement {
return context.buildStatements
}
@@ -1121,6 +1345,11 @@ func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) {
executionRoot := path.Join(ctx.Config().BazelContext.OutputBase(), "execroot", "__main__")
bazelOutDir := path.Join(executionRoot, "bazel-out")
for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
+ // nil build statements are a valid case where we do not create an action because it is
+ // unnecessary or handled by other processing
+ if buildStatement == nil {
+ continue
+ }
if len(buildStatement.Command) > 0 {
rule := NewRuleBuilder(pctx, ctx)
createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx)
@@ -1165,7 +1394,7 @@ func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) {
}
// Register bazel-owned build statements (obtained from the aquery invocation).
-func createCommand(cmd *RuleBuilderCommand, buildStatement bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx BuilderContext) {
+func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx BuilderContext) {
// executionRoot is the action cwd.
cmd.Text(fmt.Sprintf("cd '%s' &&", executionRoot))
@@ -1245,7 +1474,16 @@ func getConfigString(key cqueryKey) string {
// Use host OS, which is currently hardcoded to be linux.
osName = "linux"
}
- return arch + "|" + osName
+ keyString := arch + "|" + osName
+ if key.configKey.apexKey.WithinApex {
+ keyString += "|" + withinApexToString(key.configKey.apexKey.WithinApex)
+ }
+
+ if len(key.configKey.apexKey.ApexSdkVersion) > 0 {
+ keyString += "|" + key.configKey.apexKey.ApexSdkVersion
+ }
+
+ return keyString
}
func GetConfigKey(ctx BaseModuleContext) configKey {
@@ -1256,6 +1494,29 @@ func GetConfigKey(ctx BaseModuleContext) configKey {
}
}
+func GetConfigKeyApexVariant(ctx BaseModuleContext, apexKey *ApexConfigKey) configKey {
+ configKey := GetConfigKey(ctx)
+
+ if apexKey != nil {
+ configKey.apexKey = ApexConfigKey{
+ WithinApex: apexKey.WithinApex,
+ ApexSdkVersion: apexKey.ApexSdkVersion,
+ }
+ }
+
+ return configKey
+}
+
func bazelDepsetName(contentHash string) string {
return fmt.Sprintf("bazel_depset_%s", contentHash)
}
+
+func EnvironmentVarsFile(config Config) string {
+ return fmt.Sprintf(bazel.GeneratedBazelFileWarning+`
+_env = %s
+
+env = _env
+`,
+ starlark_fmt.PrintStringList(allowedBazelEnvironmentVars, 0),
+ )
+}
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index 013e19c96..c67d7fb66 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -11,33 +11,57 @@ import (
"android/soong/bazel/cquery"
analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
+ "github.com/google/blueprint/metrics"
"google.golang.org/protobuf/proto"
)
var testConfig = TestConfig("out", nil, "", nil)
+type testInvokeBazelContext struct{}
+
+func (t *testInvokeBazelContext) GetEventHandler() *metrics.EventHandler {
+ return &metrics.EventHandler{}
+}
+
func TestRequestResultsAfterInvokeBazel(t *testing.T) {
- label := "@//foo:bar"
- cfg := configKey{"arm64_armv8-a", Android}
+ label_foo := "@//foo:foo"
+ label_bar := "@//foo:bar"
+ apexKey := ApexConfigKey{
+ WithinApex: true,
+ ApexSdkVersion: "29",
+ }
+ cfg_foo := configKey{"arm64_armv8-a", Android, apexKey}
+ cfg_bar := configKey{arch: "arm64_armv8-a", osType: Android}
+ cmd_results := []string{
+ `@//foo:foo|arm64_armv8-a|android|within_apex|29>>out/foo/foo.txt`,
+ `@//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
+ }
bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
- bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: `@//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
+ bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: strings.Join(cmd_results, "\n"),
})
- bazelContext.QueueBazelRequest(label, cquery.GetOutputFiles, cfg)
- err := bazelContext.InvokeBazel(testConfig, nil)
+
+ bazelContext.QueueBazelRequest(label_foo, cquery.GetOutputFiles, cfg_foo)
+ bazelContext.QueueBazelRequest(label_bar, cquery.GetOutputFiles, cfg_bar)
+ err := bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
if err != nil {
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
}
- g, err := bazelContext.GetOutputFiles(label, cfg)
+ verifyCqueryResult(t, bazelContext, label_foo, cfg_foo, "out/foo/foo.txt")
+ verifyCqueryResult(t, bazelContext, label_bar, cfg_bar, "out/foo/bar.txt")
+}
+
+func verifyCqueryResult(t *testing.T, ctx *mixedBuildBazelContext, label string, cfg configKey, result string) {
+ g, err := ctx.GetOutputFiles(label, cfg)
if err != nil {
t.Errorf("Expected cquery results after running InvokeBazel(), but got err %v", err)
- } else if w := []string{"out/foo/bar.txt"}; !reflect.DeepEqual(w, g) {
+ } else if w := []string{result}; !reflect.DeepEqual(w, g) {
t.Errorf("Expected output %s, got %s", w, g)
}
}
func TestInvokeBazelWritesBazelFiles(t *testing.T) {
bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{})
- err := bazelContext.InvokeBazel(testConfig, nil)
+ err := bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
if err != nil {
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
}
@@ -118,7 +142,7 @@ func TestInvokeBazelPopulatesBuildStatements(t *testing.T) {
bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: string(data)})
- err = bazelContext.InvokeBazel(testConfig, nil)
+ err = bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
if err != nil {
t.Fatalf("testCase #%d: did not expect error invoking Bazel, but got %s", i+1, err)
}
@@ -168,10 +192,86 @@ func TestCoverageFlagsAfterInvokeBazel(t *testing.T) {
}
}
+func TestBazelRequestsSorted(t *testing.T) {
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
+
+ cfgKeyArm64Android := configKey{arch: "arm64_armv8-a", osType: Android}
+ cfgKeyArm64Linux := configKey{arch: "arm64_armv8-a", osType: Linux}
+ cfgKeyOtherAndroid := configKey{arch: "otherarch", osType: Android}
+
+ bazelContext.QueueBazelRequest("zzz", cquery.GetOutputFiles, cfgKeyArm64Android)
+ bazelContext.QueueBazelRequest("ccc", cquery.GetApexInfo, cfgKeyArm64Android)
+ bazelContext.QueueBazelRequest("duplicate", cquery.GetOutputFiles, cfgKeyArm64Android)
+ bazelContext.QueueBazelRequest("duplicate", cquery.GetOutputFiles, cfgKeyArm64Android)
+ bazelContext.QueueBazelRequest("xxx", cquery.GetOutputFiles, cfgKeyArm64Linux)
+ bazelContext.QueueBazelRequest("aaa", cquery.GetOutputFiles, cfgKeyArm64Android)
+ bazelContext.QueueBazelRequest("aaa", cquery.GetOutputFiles, cfgKeyOtherAndroid)
+ bazelContext.QueueBazelRequest("bbb", cquery.GetOutputFiles, cfgKeyOtherAndroid)
+
+ if len(bazelContext.requests) != 7 {
+ t.Error("Expected 7 request elements, but got", len(bazelContext.requests))
+ }
+
+ lastString := ""
+ for _, val := range bazelContext.requests {
+ thisString := val.String()
+ if thisString <= lastString {
+ t.Errorf("Requests are not ordered correctly. '%s' came before '%s'", lastString, thisString)
+ }
+ lastString = thisString
+ }
+}
+
+func TestIsModuleNameAllowed(t *testing.T) {
+ libDisabled := "lib_disabled"
+ libEnabled := "lib_enabled"
+ libDclaWithinApex := "lib_dcla_within_apex"
+ libDclaNonApex := "lib_dcla_non_apex"
+ libNotConverted := "lib_not_converted"
+
+ disabledModules := map[string]bool{
+ libDisabled: true,
+ }
+ enabledModules := map[string]bool{
+ libEnabled: true,
+ }
+ dclaEnabledModules := map[string]bool{
+ libDclaWithinApex: true,
+ libDclaNonApex: true,
+ }
+
+ bazelContext := &mixedBuildBazelContext{
+ modulesDefaultToBazel: false,
+ bazelEnabledModules: enabledModules,
+ bazelDisabledModules: disabledModules,
+ bazelDclaEnabledModules: dclaEnabledModules,
+ }
+
+ if bazelContext.IsModuleNameAllowed(libDisabled, true) {
+ t.Fatalf("%s shouldn't be allowed for mixed build", libDisabled)
+ }
+
+ if !bazelContext.IsModuleNameAllowed(libEnabled, true) {
+ t.Fatalf("%s should be allowed for mixed build", libEnabled)
+ }
+
+ if !bazelContext.IsModuleNameAllowed(libDclaWithinApex, true) {
+ t.Fatalf("%s should be allowed for mixed build", libDclaWithinApex)
+ }
+
+ if bazelContext.IsModuleNameAllowed(libDclaNonApex, false) {
+ t.Fatalf("%s shouldn't be allowed for mixed build", libDclaNonApex)
+ }
+
+ if bazelContext.IsModuleNameAllowed(libNotConverted, true) {
+ t.Fatalf("%s shouldn't be allowed for mixed build", libNotConverted)
+ }
+}
+
func verifyExtraFlags(t *testing.T, config Config, expected string) string {
bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
- err := bazelContext.InvokeBazel(config, nil)
+ err := bazelContext.InvokeBazel(config, &testInvokeBazelContext{})
if err != nil {
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
}
@@ -204,7 +304,6 @@ func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string)
return &mixedBuildBazelContext{
bazelRunner: runner,
paths: &p,
- requests: map[cqueryKey]bool{},
}, p.soongOutDir
}
diff --git a/android/config.go b/android/config.go
index c30511494..6412cb73d 100644
--- a/android/config.go
+++ b/android/config.go
@@ -87,6 +87,8 @@ type CmdArgs struct {
BazelModeDev bool
BazelModeStaging bool
BazelForceEnabledModules string
+
+ UseBazelProxy bool
}
// Build modes that soong_build can run as.
@@ -251,6 +253,10 @@ type config struct {
// specified modules. They are passed via the command-line flag
// "--bazel-force-enabled-modules"
bazelForceEnabledModules map[string]struct{}
+
+ // If true, for any requests to Bazel, communicate with a Bazel proxy using
+ // unix sockets, instead of spawning Bazel as a subprocess.
+ UseBazelProxy bool
}
type deviceConfig struct {
@@ -397,11 +403,13 @@ product_var_constraints = _product_var_constraints
arch_variant_product_var_constraints = _arch_variant_product_var_constraints
`,
}
- err = os.WriteFile(filepath.Join(dir, "product_variables.bzl"), []byte(strings.Join(bzl, "\n")), 0644)
+ err = pathtools.WriteFileIfChanged(filepath.Join(dir, "product_variables.bzl"),
+ []byte(strings.Join(bzl, "\n")), 0644)
if err != nil {
return fmt.Errorf("Could not write .bzl config file %s", err)
}
- err = os.WriteFile(filepath.Join(dir, "BUILD"), []byte(bazel.GeneratedBazelFileWarning), 0644)
+ err = pathtools.WriteFileIfChanged(filepath.Join(dir, "BUILD"),
+ []byte(bazel.GeneratedBazelFileWarning), 0644)
if err != nil {
return fmt.Errorf("Could not write BUILD config file %s", err)
}
@@ -440,6 +448,8 @@ func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error)
mixedBuildDisabledModules: make(map[string]struct{}),
mixedBuildEnabledModules: make(map[string]struct{}),
bazelForceEnabledModules: make(map[string]struct{}),
+
+ UseBazelProxy: cmdArgs.UseBazelProxy,
}
config.deviceConfig = &deviceConfig{
@@ -725,10 +735,6 @@ func (c *config) IsEnvFalse(key string) bool {
return value == "0" || value == "n" || value == "no" || value == "off" || value == "false"
}
-func (c *config) TargetsJava17() bool {
- return c.IsEnvTrue("EXPERIMENTAL_TARGET_JAVA_VERSION_17")
-}
-
// EnvDeps returns the environment variables this build depends on. The first
// call to this function blocks future reads from the environment.
func (c *config) EnvDeps() map[string]string {
diff --git a/android/defaults.go b/android/defaults.go
index 7906e946c..a821b286e 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -55,7 +55,7 @@ func (d *DefaultableModuleBase) SetDefaultableHook(hook DefaultableHook) {
d.hook = hook
}
-func (d *DefaultableModuleBase) callHookIfAvailable(ctx DefaultableHookContext) {
+func (d *DefaultableModuleBase) CallHookIfAvailable(ctx DefaultableHookContext) {
if d.hook != nil {
d.hook(ctx)
}
@@ -82,7 +82,7 @@ type Defaultable interface {
SetDefaultableHook(hook DefaultableHook)
// Call the hook if specified.
- callHookIfAvailable(context DefaultableHookContext)
+ CallHookIfAvailable(context DefaultableHookContext)
}
type DefaultableModule interface {
@@ -302,7 +302,7 @@ func InitDefaultsModule(module DefaultsModule) {
delete(propertiesSet, "visibility")
// Replace the "*" with the names of all the properties that have been set.
- protectedProperties = SortedStringKeys(propertiesSet)
+ protectedProperties = SortedKeys(propertiesSet)
module.setProtectedProperties(protectedProperties)
} else {
for _, property := range protectedProperties {
@@ -630,6 +630,6 @@ func defaultsMutator(ctx TopDownMutatorContext) {
defaultable.applyDefaults(ctx, defaultsList)
}
- defaultable.callHookIfAvailable(ctx)
+ defaultable.CallHookIfAvailable(ctx)
}
}
diff --git a/android/defs.go b/android/defs.go
index 6e5bb053f..18eed2dae 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -58,6 +58,14 @@ var (
},
"cpFlags", "extraCmds")
+ // A copy rule that doesn't preserve symlinks.
+ CpNoPreserveSymlink = pctx.AndroidStaticRule("CpNoPreserveSymlink",
+ blueprint.RuleParams{
+ Command: "rm -f $out && cp $cpFlags $in $out$extraCmds",
+ Description: "cp $out",
+ },
+ "cpFlags", "extraCmds")
+
// A copy rule that only updates the output if it changed.
CpIfChanged = pctx.AndroidStaticRule("CpIfChanged",
blueprint.RuleParams{
diff --git a/android/filegroup.go b/android/filegroup.go
index d21d146f4..7d929bc4e 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -232,7 +232,7 @@ func (fg *fileGroup) QueueBazelCall(ctx BaseModuleContext) {
bazelCtx.QueueBazelRequest(
fg.GetBazelLabel(ctx, fg),
cquery.GetOutputFiles,
- configKey{Common.String(), CommonOS})
+ configKey{arch: Common.String(), osType: CommonOS})
}
func (fg *fileGroup) IsMixedBuildSupported(ctx BaseModuleContext) bool {
@@ -252,7 +252,7 @@ func (fg *fileGroup) ProcessBazelQueryResponse(ctx ModuleContext) {
relativeRoot = filepath.Join(relativeRoot, *fg.properties.Path)
}
- filePaths, err := bazelCtx.GetOutputFiles(fg.GetBazelLabel(ctx, fg), configKey{Common.String(), CommonOS})
+ filePaths, err := bazelCtx.GetOutputFiles(fg.GetBazelLabel(ctx, fg), configKey{arch: Common.String(), osType: CommonOS})
if err != nil {
ctx.ModuleErrorf(err.Error())
return
diff --git a/android/module.go b/android/module.go
index 681f724b0..58c54642a 100644
--- a/android/module.go
+++ b/android/module.go
@@ -502,6 +502,7 @@ type Module interface {
InstallInRoot() bool
InstallInVendor() bool
InstallForceOS() (*OsType, *ArchType)
+ PartitionTag(DeviceConfig) string
HideFromMake()
IsHideFromMake() bool
IsSkipInstall() bool
@@ -3674,7 +3675,7 @@ func AddAncestors(ctx SingletonContext, dirMap map[string]Paths, mmName func(str
// Ensure ancestor directories are in dirMap
// Make directories build their direct subdirectories
// Returns a slice of all directories and a slice of top-level directories.
- dirs := SortedStringKeys(dirMap)
+ dirs := SortedKeys(dirMap)
for _, dir := range dirs {
dir := parentDir(dir)
for dir != "." && dir != "/" {
@@ -3685,7 +3686,7 @@ func AddAncestors(ctx SingletonContext, dirMap map[string]Paths, mmName func(str
dir = parentDir(dir)
}
}
- dirs = SortedStringKeys(dirMap)
+ dirs = SortedKeys(dirMap)
var topDirs []string
for _, dir := range dirs {
p := parentDir(dir)
@@ -3695,7 +3696,7 @@ func AddAncestors(ctx SingletonContext, dirMap map[string]Paths, mmName func(str
topDirs = append(topDirs, dir)
}
}
- return SortedStringKeys(dirMap), topDirs
+ return SortedKeys(dirMap), topDirs
}
func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) {
@@ -3781,7 +3782,7 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) {
}
// Wrap those into host|host-cross|target phony rules
- for _, class := range SortedStringKeys(osClass) {
+ for _, class := range SortedKeys(osClass) {
ctx.Phony(class, osClass[class]...)
}
}
diff --git a/android/mutator.go b/android/mutator.go
index 4e55609ae..4dacb8df8 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -709,24 +709,29 @@ func (t *topDownMutatorContext) CreateBazelTargetModuleWithRestrictions(
// module and returns it as a list of keyed tags.
func ApexAvailableTags(mod Module) bazel.StringListAttribute {
attr := bazel.StringListAttribute{}
- tags := []string{}
// Transform specific attributes into tags.
if am, ok := mod.(ApexModule); ok {
// TODO(b/218841706): hidl_interface has the apex_available prop, but it's
// defined directly as a prop and not via ApexModule, so this doesn't
// pick those props up.
- // TODO(b/260694842): This does not pick up aidl_interface.backend.ndk.apex_available.
- for _, a := range am.apexModuleBase().ApexAvailable() {
- tags = append(tags, "apex_available="+a)
- }
- }
- if len(tags) > 0 {
- // This avoids creating a tags attr with an empty list if there are no tags.
- attr.Value = tags
+ attr.Value = ConvertApexAvailableToTags(am.apexModuleBase().ApexAvailable())
}
return attr
}
+func ConvertApexAvailableToTags(apexAvailable []string) []string {
+ if len(apexAvailable) == 0 {
+ // We need nil specifically to make bp2build not add the tags property at all,
+ // instead of adding it with an empty list
+ return nil
+ }
+ result := make([]string, 0, len(apexAvailable))
+ for _, a := range apexAvailable {
+ result = append(result, "apex_available="+a)
+ }
+ return result
+}
+
func (t *topDownMutatorContext) createBazelTargetModule(
bazelProps bazel.BazelTargetModuleProperties,
commonAttrs CommonAttributes,
diff --git a/android/mutator_test.go b/android/mutator_test.go
index 21eebd2c8..dbdfa3362 100644
--- a/android/mutator_test.go
+++ b/android/mutator_test.go
@@ -16,6 +16,7 @@ package android
import (
"fmt"
+ "reflect"
"strings"
"testing"
@@ -267,3 +268,22 @@ func TestNoCreateVariationsInFinalDeps(t *testing.T) {
FixtureWithRootAndroidBp(`test {name: "foo"}`),
).RunTest(t)
}
+
+func TestConvertApexAvailableToTags(t *testing.T) {
+ input := []string{
+ "com.android.adbd",
+ "//apex_available:platform",
+ }
+ actual := ConvertApexAvailableToTags(input)
+ expected := []string{
+ "apex_available=com.android.adbd",
+ "apex_available=//apex_available:platform",
+ }
+ if !reflect.DeepEqual(actual, expected) {
+ t.Errorf("Expected: %v, actual: %v", expected, actual)
+ }
+
+ if ConvertApexAvailableToTags(nil) != nil {
+ t.Errorf("Expected providing nil to return nil")
+ }
+}
diff --git a/android/neverallow.go b/android/neverallow.go
index ad9880ad6..ba5385cd2 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -542,7 +542,7 @@ func (r *rule) String() string {
s = append(s, fmt.Sprintf("properties matching: %s", r.props))
}
if len(r.directDeps) > 0 {
- s = append(s, fmt.Sprintf("dep(s): %q", SortedStringKeys(r.directDeps)))
+ s = append(s, fmt.Sprintf("dep(s): %q", SortedKeys(r.directDeps)))
}
if len(r.osClasses) > 0 {
s = append(s, fmt.Sprintf("os class(es): %q", r.osClasses))
diff --git a/android/packaging.go b/android/packaging.go
index ecd84a2f0..4a9b59172 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -240,7 +240,7 @@ func (p *PackagingBase) GatherPackagingSpecs(ctx ModuleContext) map[string]Packa
// entries into the specified directory.
func (p *PackagingBase) CopySpecsToDir(ctx ModuleContext, builder *RuleBuilder, specs map[string]PackagingSpec, dir ModuleOutPath) (entries []string) {
seenDir := make(map[string]bool)
- for _, k := range SortedStringKeys(specs) {
+ for _, k := range SortedKeys(specs) {
ps := specs[k]
destPath := dir.Join(ctx, ps.relPathInPackage).String()
destDir := filepath.Dir(destPath)
diff --git a/android/paths.go b/android/paths.go
index 0fc39df6c..eaa6a8d0b 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -16,7 +16,6 @@ package android
import (
"fmt"
- "io/ioutil"
"os"
"path/filepath"
"reflect"
@@ -1710,10 +1709,10 @@ func makePathForInstall(ctx ModuleInstallPathContext, os OsType, arch ArchType,
func pathForInstall(ctx PathContext, os OsType, arch ArchType, partition string, debug bool,
pathComponents ...string) InstallPath {
- var partionPaths []string
+ var partitionPaths []string
if os.Class == Device {
- partionPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
+ partitionPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
} else {
osName := os.String()
if os == Linux {
@@ -1735,21 +1734,21 @@ func pathForInstall(ctx PathContext, os OsType, arch ArchType, partition string,
if os.Class == Host && (arch == X86_64 || arch == Common) {
archName = "x86"
}
- partionPaths = []string{"host", osName + "-" + archName, partition}
+ partitionPaths = []string{"host", osName + "-" + archName, partition}
}
if debug {
- partionPaths = append([]string{"debug"}, partionPaths...)
+ partitionPaths = append([]string{"debug"}, partitionPaths...)
}
- partionPath, err := validatePath(partionPaths...)
+ partitionPath, err := validatePath(partitionPaths...)
if err != nil {
reportPathError(ctx, err)
}
base := InstallPath{
- basePath: basePath{partionPath, ""},
+ basePath: basePath{partitionPath, ""},
soongOutDir: ctx.Config().soongOutDir,
- partitionDir: partionPath,
+ partitionDir: partitionPath,
partition: partition,
}
@@ -1868,10 +1867,14 @@ func (p InstallPaths) Strings() []string {
return ret
}
-// validateSafePath validates a path that we trust (may contain ninja variables).
-// Ensures that each path component does not attempt to leave its component.
-func validateSafePath(pathComponents ...string) (string, error) {
+// validatePathInternal ensures that a path does not leave its component, and
+// optionally doesn't contain Ninja variables.
+func validatePathInternal(allowNinjaVariables bool, pathComponents ...string) (string, error) {
for _, path := range pathComponents {
+ if !allowNinjaVariables && strings.Contains(path, "$") {
+ return "", fmt.Errorf("Path contains invalid character($): %s", path)
+ }
+
path := filepath.Clean(path)
if path == ".." || strings.HasPrefix(path, "../") || strings.HasPrefix(path, "/") {
return "", fmt.Errorf("Path is outside directory: %s", path)
@@ -1883,16 +1886,18 @@ func validateSafePath(pathComponents ...string) (string, error) {
return filepath.Join(pathComponents...), nil
}
+// validateSafePath validates a path that we trust (may contain ninja
+// variables). Ensures that each path component does not attempt to leave its
+// component. Returns a joined version of each path component.
+func validateSafePath(pathComponents ...string) (string, error) {
+ return validatePathInternal(true, pathComponents...)
+}
+
// validatePath validates that a path does not include ninja variables, and that
// each path component does not attempt to leave its component. Returns a joined
// version of each path component.
func validatePath(pathComponents ...string) (string, error) {
- for _, path := range pathComponents {
- if strings.Contains(path, "$") {
- return "", fmt.Errorf("Path contains invalid character($): %s", path)
- }
- }
- return validateSafePath(pathComponents...)
+ return validatePathInternal(false, pathComponents...)
}
func PathForPhony(ctx PathContext, phony string) WritablePath {
@@ -2093,13 +2098,16 @@ func maybeRelErr(basePath string, targetPath string) (string, bool, error) {
// Writes a file to the output directory. Attempting to write directly to the output directory
// will fail due to the sandbox of the soong_build process.
+// Only writes the file if the file doesn't exist or if it has different contents, to prevent
+// updating the timestamp if no changes would be made. (This is better for incremental
+// performance.)
func WriteFileToOutputDir(path WritablePath, data []byte, perm os.FileMode) error {
absPath := absolutePath(path.String())
err := os.MkdirAll(filepath.Dir(absPath), 0777)
if err != nil {
return err
}
- return ioutil.WriteFile(absPath, data, perm)
+ return pathtools.WriteFileIfChanged(absPath, data, perm)
}
func RemoveAllOutputDir(path WritablePath) error {
diff --git a/android/phony.go b/android/phony.go
index 0adbb55b5..814a9e30a 100644
--- a/android/phony.go
+++ b/android/phony.go
@@ -48,7 +48,7 @@ var _ SingletonMakeVarsProvider = (*phonySingleton)(nil)
func (p *phonySingleton) GenerateBuildActions(ctx SingletonContext) {
p.phonyMap = getPhonyMap(ctx.Config())
- p.phonyList = SortedStringKeys(p.phonyMap)
+ p.phonyList = SortedKeys(p.phonyMap)
for _, phony := range p.phonyList {
p.phonyMap[phony] = SortedUniquePaths(p.phonyMap[phony])
}
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 8953eaecd..a7e03dcd8 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -211,7 +211,29 @@ func (s SdkSpec) EffectiveVersionString(ctx EarlyModuleContext) (string, error)
if !s.ApiLevel.IsPreview() {
return s.ApiLevel.String(), nil
}
- return ctx.Config().DefaultAppTargetSdk(ctx).String(), nil
+ // Determine the default sdk
+ ret := ctx.Config().DefaultAppTargetSdk(ctx)
+ if !ret.IsPreview() {
+ // If the default sdk has been finalized, return that
+ return ret.String(), nil
+ }
+ // There can be more than one active in-development sdks
+ // If an app is targeting an active sdk, but not the default one, return the requested active sdk.
+ // e.g.
+ // SETUP
+ // In-development: UpsideDownCake, VanillaIceCream
+ // Default: VanillaIceCream
+ // Android.bp
+ // min_sdk_version: `UpsideDownCake`
+ // RETURN
+ // UpsideDownCake and not VanillaIceCream
+ for _, preview := range ctx.Config().PreviewApiLevels() {
+ if s.ApiLevel.String() == preview.String() {
+ return preview.String(), nil
+ }
+ }
+ // Otherwise return the default one
+ return ret.String(), nil
}
var (
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index ed4888d3d..9239ca950 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -301,23 +301,6 @@ func (defs *Bp2BuildSoongConfigDefinitions) AddVars(mtDef SoongConfigDefinition)
}
}
-// This is a copy of the one available in soong/android/util.go, but depending
-// on the android package causes a cyclic dependency. A refactoring here is to
-// extract common utils out from android/utils.go for other packages like this.
-func sortedStringKeys(m interface{}) []string {
- v := reflect.ValueOf(m)
- if v.Kind() != reflect.Map {
- panic(fmt.Sprintf("%#v is not a map", m))
- }
- keys := v.MapKeys()
- s := make([]string, 0, len(keys))
- for _, key := range keys {
- s = append(s, key.String())
- }
- sort.Strings(s)
- return s
-}
-
// String emits the Soong config variable definitions as Starlark dictionaries.
func (defs Bp2BuildSoongConfigDefinitions) String() string {
ret := ""
diff --git a/android/test_suites.go b/android/test_suites.go
index 55e1da79c..b570b2383 100644
--- a/android/test_suites.go
+++ b/android/test_suites.go
@@ -57,7 +57,7 @@ func (t *testSuiteFiles) MakeVars(ctx MakeVarsContext) {
func robolectricTestSuite(ctx SingletonContext, files map[string]InstallPaths) WritablePath {
var installedPaths InstallPaths
- for _, module := range SortedStringKeys(files) {
+ for _, module := range SortedKeys(files) {
installedPaths = append(installedPaths, files[module]...)
}
testCasesDir := pathForInstall(ctx, ctx.Config().BuildOS, X86, "testcases", false)
diff --git a/android/util.go b/android/util.go
index 947af699c..38e0a4dbb 100644
--- a/android/util.go
+++ b/android/util.go
@@ -29,6 +29,15 @@ func CopyOf(s []string) []string {
return append([]string(nil), s...)
}
+// Concat returns a new slice concatenated from the two input slices. It does not change the input
+// slices.
+func Concat[T any](s1, s2 []T) []T {
+ res := make([]T, 0, len(s1)+len(s2))
+ res = append(res, s1...)
+ res = append(res, s2...)
+ return res
+}
+
// JoinWithPrefix prepends the prefix to each string in the list and
// returns them joined together with " " as separator.
func JoinWithPrefix(strs []string, prefix string) string {
@@ -53,40 +62,33 @@ func JoinWithPrefixAndSeparator(strs []string, prefix string, sep string) string
return buf.String()
}
-// JoinWithSuffix appends the suffix to each string in the list and
-// returns them joined together with given separator.
-func JoinWithSuffix(strs []string, suffix string, separator string) string {
- if len(strs) == 0 {
- return ""
- }
+// SortedStringKeys returns the keys of the given map in the ascending order.
+//
+// Deprecated: Use SortedKeys instead.
+func SortedStringKeys[V any](m map[string]V) []string {
+ return SortedKeys(m)
+}
- var buf strings.Builder
- buf.WriteString(strs[0])
- buf.WriteString(suffix)
- for i := 1; i < len(strs); i++ {
- buf.WriteString(separator)
- buf.WriteString(strs[i])
- buf.WriteString(suffix)
- }
- return buf.String()
+type Ordered interface {
+ ~string |
+ ~float32 | ~float64 |
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
}
-// SorterStringKeys returns the keys of the given string-keyed map in the ascending order.
-func SortedStringKeys(m interface{}) []string {
- v := reflect.ValueOf(m)
- if v.Kind() != reflect.Map {
- panic(fmt.Sprintf("%#v is not a map", m))
- }
- if v.Len() == 0 {
+// SortedKeys returns the keys of the given map in the ascending order.
+func SortedKeys[T Ordered, V any](m map[T]V) []T {
+ if len(m) == 0 {
return nil
}
- iter := v.MapRange()
- s := make([]string, 0, v.Len())
- for iter.Next() {
- s = append(s, iter.Key().String())
+ ret := make([]T, 0, len(m))
+ for k := range m {
+ ret = append(ret, k)
}
- sort.Strings(s)
- return s
+ sort.Slice(ret, func(i, j int) bool {
+ return ret[i] < ret[j]
+ })
+ return ret
}
// stringValues returns the values of the given string-valued map in randomized map order.
diff --git a/android/util_test.go b/android/util_test.go
index 9b9253b49..1034d9e5c 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -641,42 +641,34 @@ func BenchmarkFirstUniqueStrings(b *testing.B) {
}
}
-func TestSortedStringKeys(t *testing.T) {
- testCases := []struct {
- name string
- in interface{}
- expected []string
- }{
- {
- name: "nil",
- in: map[string]string(nil),
- expected: nil,
- },
- {
- name: "empty",
- in: map[string]string{},
- expected: nil,
- },
- {
- name: "simple",
- in: map[string]string{"a": "foo", "b": "bar"},
- expected: []string{"a", "b"},
- },
- {
- name: "interface values",
- in: map[string]interface{}{"a": nil, "b": nil},
- expected: []string{"a", "b"},
- },
- }
+func testSortedKeysHelper[K Ordered, V any](t *testing.T, name string, input map[K]V, expected []K) {
+ t.Helper()
+ t.Run(name, func(t *testing.T) {
+ actual := SortedKeys(input)
+ if !reflect.DeepEqual(actual, expected) {
+ t.Errorf("expected %q, got %q", expected, actual)
+ }
+ })
+}
- for _, tt := range testCases {
- t.Run(tt.name, func(t *testing.T) {
- got := SortedStringKeys(tt.in)
- if g, w := got, tt.expected; !reflect.DeepEqual(g, w) {
- t.Errorf("wanted %q, got %q", w, g)
- }
- })
- }
+func TestSortedKeys(t *testing.T) {
+ testSortedKeysHelper(t, "simple", map[string]string{
+ "b": "bar",
+ "a": "foo",
+ }, []string{
+ "a",
+ "b",
+ })
+ testSortedKeysHelper(t, "ints", map[int]interface{}{
+ 10: nil,
+ 5: nil,
+ }, []int{
+ 5,
+ 10,
+ })
+
+ testSortedKeysHelper(t, "nil", map[string]string(nil), nil)
+ testSortedKeysHelper(t, "empty", map[string]string{}, nil)
}
func TestSortedStringValues(t *testing.T) {
diff --git a/android/variable.go b/android/variable.go
index e714fc49a..f7ac7d682 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -64,6 +64,12 @@ type variableProperties struct {
Enabled *bool `android:"arch_variant"`
} `android:"arch_variant"`
+ // similar to `Unbundled_build`, but `Always_use_prebuilt_sdks` means that it uses prebuilt
+ // sdk specifically.
+ Always_use_prebuilt_sdks struct {
+ Enabled *bool `android:"arch_variant"`
+ } `android:"arch_variant"`
+
Malloc_not_svelte struct {
Cflags []string `android:"arch_variant"`
Shared_libs []string `android:"arch_variant"`
diff --git a/android_sdk/sdk_repo_host.go b/android_sdk/sdk_repo_host.go
index f64674276..61058df09 100644
--- a/android_sdk/sdk_repo_host.go
+++ b/android_sdk/sdk_repo_host.go
@@ -166,10 +166,9 @@ func (s *sdkRepoHost) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
} else {
llvmStrip := config.ClangPath(ctx, "bin/llvm-strip")
- llvmLib64 := config.ClangPath(ctx, "lib64/libc++.so.1")
- llvmLib := config.ClangPath(ctx, "lib/libc++.so.1")
+ llvmLib := config.ClangPath(ctx, "lib/x86_64-unknown-linux-gnu/libc++.so.1")
for _, strip := range s.properties.Strip_files {
- cmd := builder.Command().Tool(llvmStrip).ImplicitTool(llvmLib64).ImplicitTool(llvmLib)
+ cmd := builder.Command().Tool(llvmStrip).ImplicitTool(llvmLib)
if !ctx.Windows() {
cmd.Flag("-x")
}
diff --git a/apex/OWNERS b/apex/OWNERS
deleted file mode 100644
index 8e4ba5cd5..000000000
--- a/apex/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-per-file * = jiyong@google.com
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 7babd45ba..7f0362109 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -23,8 +23,7 @@ import (
"android/soong/android"
"android/soong/cc"
"android/soong/java"
-
- "github.com/google/blueprint/proptools"
+ "android/soong/rust"
)
func (a *apexBundle) AndroidMk() android.AndroidMkData {
@@ -73,12 +72,15 @@ func (a *apexBundle) fullModuleName(apexBundleName string, fi *apexFile) string
return fi.androidMkModuleName + "." + apexBundleName + a.suffix
}
-func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, moduleDir string,
+func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, moduleDir string,
apexAndroidMkData android.AndroidMkData) []string {
- // apexBundleName comes from the 'name' property; apexName comes from 'apex_name' property.
+ // apexBundleName comes from the 'name' property or soong module.
+ // apexName comes from 'name' property of apex_manifest.
// An apex is installed to /system/apex/<apexBundleName> and is activated at /apex/<apexName>
// In many cases, the two names are the same, but could be different in general.
+ // However, symbol files for apex files are installed under /apex/<apexBundleName> to avoid
+ // conflicts between two apexes with the same apexName.
moduleNames := []string{}
apexType := a.properties.ApexType
@@ -89,25 +91,6 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo
return moduleNames
}
- // b/162366062. Prevent GKI APEXes to emit make rules to avoid conflicts.
- if strings.HasPrefix(apexName, "com.android.gki.") && apexType != flattenedApex {
- return moduleNames
- }
-
- // b/140136207. When there are overriding APEXes for a VNDK APEX, the symbols file for the overridden
- // APEX and the overriding APEX will have the same installation paths at /apex/com.android.vndk.v<ver>
- // as their apexName will be the same. To avoid the path conflicts, skip installing the symbol files
- // for the overriding VNDK APEXes.
- symbolFilesNotNeeded := a.vndkApex && len(a.overridableProperties.Overrides) > 0
- if symbolFilesNotNeeded && apexType != flattenedApex {
- return moduleNames
- }
-
- // Avoid creating duplicate build rules for multi-installed APEXes.
- if proptools.BoolDefault(a.properties.Multi_install_skip_symbol_files, false) {
- return moduleNames
- }
-
seenDataOutPaths := make(map[string]bool)
for _, fi := range a.filesInfo {
@@ -144,15 +127,15 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo
if fi.module != nil && fi.module.Owner() != "" {
fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", fi.module.Owner())
}
- // /apex/<apex_name>/{lib|framework|...}
- pathWhenActivated := filepath.Join("$(PRODUCT_OUT)", "apex", apexName, fi.installDir)
+ // /apex/<apexBundleName>/{lib|framework|...}
+ pathForSymbol := filepath.Join("$(PRODUCT_OUT)", "apex", apexBundleName, fi.installDir)
var modulePath string
if apexType == flattenedApex {
- // /system/apex/<name>/{lib|framework|...}
+ // /system/apex/<apexBundleName>/{lib|framework|...}
modulePath = filepath.Join(a.installDir.String(), apexBundleName, fi.installDir)
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", modulePath)
- if a.primaryApexType && !symbolFilesNotNeeded {
- fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathWhenActivated)
+ if a.primaryApexType {
+ fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathForSymbol)
}
android.AndroidMkEmitAssignList(w, "LOCAL_MODULE_SYMLINKS", fi.symlinks)
newDataPaths := []android.DataPath{}
@@ -165,8 +148,8 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo
}
android.AndroidMkEmitAssignList(w, "LOCAL_TEST_DATA", android.AndroidMkDataPaths(newDataPaths))
} else {
- modulePath = pathWhenActivated
- fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", pathWhenActivated)
+ modulePath = pathForSymbol
+ fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", modulePath)
// For non-flattend APEXes, the merged notice file is attached to the APEX itself.
// We don't need to have notice file for the individual modules in it. Otherwise,
@@ -256,6 +239,10 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo
if ccMod.CoverageOutputFile().Valid() {
fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", ccMod.CoverageOutputFile().String())
}
+ } else if rustMod, ok := fi.module.(*rust.Module); ok {
+ if rustMod.UnstrippedOutputFile() != nil {
+ fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", rustMod.UnstrippedOutputFile().String())
+ }
}
fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk")
default:
@@ -320,8 +307,7 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData {
moduleNames := []string{}
apexType := a.properties.ApexType
if a.installable() {
- apexName := proptools.StringDefault(a.properties.Apex_name, name)
- moduleNames = a.androidMkForFiles(w, name, apexName, moduleDir, data)
+ moduleNames = a.androidMkForFiles(w, name, moduleDir, data)
}
if apexType == flattenedApex {
diff --git a/apex/apex.go b/apex/apex.go
index a9c8afce7..88eb72fef 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -94,15 +94,15 @@ type apexBundleProperties struct {
// a default one is automatically generated.
AndroidManifest *string `android:"path"`
- // Canonical name of this APEX bundle. Used to determine the path to the activated APEX on
- // device (/apex/<apex_name>). If unspecified, follows the name property.
- Apex_name *string
-
// Determines the file contexts file for setting the security contexts to files in this APEX
// bundle. For platform APEXes, this should points to a file under /system/sepolicy Default:
// /system/sepolicy/apex/<module_name>_file_contexts.
File_contexts *string `android:"path"`
+ // By default, file_contexts is amended by force-labelling / and /apex_manifest.pb as system_file
+ // to avoid mistakes. When set as true, no force-labelling.
+ Use_file_contexts_as_is *bool
+
// Path to the canned fs config file for customizing file's uid/gid/mod/capabilities. The
// format is /<path_or_glob> <uid> <gid> <mode> [capabilities=0x<cap>], where path_or_glob is a
// path or glob pattern for a file or set of files, uid/gid are numerial values of user ID
@@ -115,6 +115,18 @@ type apexBundleProperties struct {
Multilib apexMultilibProperties
+ // List of runtime resource overlays (RROs) that are embedded inside this APEX.
+ Rros []string
+
+ // List of bootclasspath fragments that are embedded inside this APEX bundle.
+ Bootclasspath_fragments []string
+
+ // List of systemserverclasspath fragments that are embedded inside this APEX bundle.
+ Systemserverclasspath_fragments []string
+
+ // List of java libraries that are embedded inside this APEX bundle.
+ Java_libs []string
+
// List of sh binaries that are embedded inside this APEX bundle.
Sh_binaries []string
@@ -149,16 +161,6 @@ type apexBundleProperties struct {
// Should be only used in non-system apexes (e.g. vendor: true). Default is false.
Use_vndk_as_stable *bool
- // Whether this is multi-installed APEX should skip installing symbol files.
- // Multi-installed APEXes share the same apex_name and are installed at the same time.
- // Default is false.
- //
- // Should be set to true for all multi-installed APEXes except the singular
- // default version within the multi-installed group.
- // Only the default version can install symbol files in $(PRODUCT_OUT}/apex,
- // or else conflicting build rules may be created.
- Multi_install_skip_symbol_files *bool
-
// The type of APEX to build. Controls what the APEX payload is. Either 'image', 'zip' or
// 'both'. When set to image, contents are stored in a filesystem image inside a zip
// container. When set to zip, contents are stored in a zip container directly. This type is
@@ -340,21 +342,9 @@ type overridableProperties struct {
// List of prebuilt files that are embedded inside this APEX bundle.
Prebuilts []string
- // List of runtime resource overlays (RROs) that are embedded inside this APEX.
- Rros []string
-
// List of BPF programs inside this APEX bundle.
Bpfs []string
- // List of bootclasspath fragments that are embedded inside this APEX bundle.
- Bootclasspath_fragments []string
-
- // List of systemserverclasspath fragments that are embedded inside this APEX bundle.
- Systemserverclasspath_fragments []string
-
- // List of java libraries that are embedded inside this APEX bundle.
- Java_libs []string
-
// Names of modules to be overridden. Listed modules can only be other binaries (in Make or
// Soong). This does not completely prevent installation of the overridden binaries, but if
// both binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will
@@ -528,6 +518,7 @@ type apexFile struct {
// buildFile is put in the installDir inside the APEX.
builtFile android.Path
installDir string
+ partition string
customStem string
symlinks []string // additional symlinks
@@ -567,6 +558,7 @@ func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, androidM
}
if module != nil {
ret.moduleDir = ctx.OtherModuleDir(module)
+ ret.partition = module.PartitionTag(ctx.DeviceConfig())
ret.requiredModuleNames = module.RequiredModuleNames()
ret.targetRequiredModuleNames = module.TargetRequiredModuleNames()
ret.hostRequiredModuleNames = module.HostRequiredModuleNames()
@@ -859,6 +851,10 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) {
// Common-arch dependencies come next
commonVariation := ctx.Config().AndroidCommonTarget.Variations()
+ ctx.AddFarVariationDependencies(commonVariation, rroTag, a.properties.Rros...)
+ ctx.AddFarVariationDependencies(commonVariation, bcpfTag, a.properties.Bootclasspath_fragments...)
+ ctx.AddFarVariationDependencies(commonVariation, sscpfTag, a.properties.Systemserverclasspath_fragments...)
+ ctx.AddFarVariationDependencies(commonVariation, javaLibTag, a.properties.Java_libs...)
ctx.AddFarVariationDependencies(commonVariation, fsTag, a.properties.Filesystems...)
ctx.AddFarVariationDependencies(commonVariation, compatConfigTag, a.properties.Compat_configs...)
}
@@ -872,10 +868,6 @@ func (a *apexBundle) OverridablePropertiesDepsMutator(ctx android.BottomUpMutato
commonVariation := ctx.Config().AndroidCommonTarget.Variations()
ctx.AddFarVariationDependencies(commonVariation, androidAppTag, a.overridableProperties.Apps...)
ctx.AddFarVariationDependencies(commonVariation, bpfTag, a.overridableProperties.Bpfs...)
- ctx.AddFarVariationDependencies(commonVariation, rroTag, a.overridableProperties.Rros...)
- ctx.AddFarVariationDependencies(commonVariation, bcpfTag, a.overridableProperties.Bootclasspath_fragments...)
- ctx.AddFarVariationDependencies(commonVariation, sscpfTag, a.overridableProperties.Systemserverclasspath_fragments...)
- ctx.AddFarVariationDependencies(commonVariation, javaLibTag, a.overridableProperties.Java_libs...)
if prebuilts := a.overridableProperties.Prebuilts; len(prebuilts) > 0 {
// For prebuilt_etc, use the first variant (64 on 64/32bit device, 32 on 32bit device)
// regardless of the TARGET_PREFER_* setting. See b/144532908
@@ -1047,7 +1039,7 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) {
// This is the main part of this mutator. Mark the collected dependencies that they need to
// be built for this apexBundle.
- apexVariationName := proptools.StringDefault(a.properties.Apex_name, mctx.ModuleName()) // could be com.android.foo
+ apexVariationName := mctx.ModuleName() // could be com.android.foo
a.properties.ApexVariationName = apexVariationName
apexInfo := android.ApexInfo{
ApexVariationName: apexVariationName,
@@ -1781,6 +1773,18 @@ func apexFileForJavaModuleWithFile(ctx android.BaseModuleContext, module javaMod
return af
}
+func apexFileForJavaModuleProfile(ctx android.BaseModuleContext, module javaModule) *apexFile {
+ if dexpreopter, ok := module.(java.DexpreopterInterface); ok {
+ if profilePathOnHost := dexpreopter.OutputProfilePathOnHost(); profilePathOnHost != nil {
+ dirInApex := "javalib"
+ af := newApexFile(ctx, profilePathOnHost, module.BaseModuleName()+"-profile", dirInApex, etc, nil)
+ af.customStem = module.Stem() + ".jar.prof"
+ return &af
+ }
+ }
+ return nil
+}
+
// androidApp is an interface to handle all app modules (android_app, android_app_import, etc.) in
// the same way.
type androidApp interface {
@@ -1964,6 +1968,11 @@ func (a *apexBundle) ProcessBazelQueryResponse(ctx android.ModuleContext) {
}
a.outputFile = a.outputApexFile
+ if len(outputs.TidyFiles) > 0 {
+ tidyFiles := android.PathsForBazelOut(ctx, outputs.TidyFiles)
+ a.outputFile = android.AttachValidationActions(ctx, a.outputFile, tidyFiles)
+ }
+
// TODO(b/257829940): These are used by the apex_keys_text singleton; would probably be a clearer
// interface if these were set in a provider rather than the module itself
a.publicKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyInfo[0])
@@ -1991,21 +2000,17 @@ func (a *apexBundle) ProcessBazelQueryResponse(ctx android.ModuleContext) {
a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile,
a.compatSymlinks.Paths()...)
default:
- panic(fmt.Errorf("unexpected apex_type for the ProcessBazelQuery: %v", a.properties.ApexType))
+ panic(fmt.Errorf("internal error: unexpected apex_type for the ProcessBazelQueryResponse: %v", a.properties.ApexType))
}
- /*
- TODO(asmundak): compared to building an APEX with Soong, building it with Bazel does not
- return filesInfo and requiredDeps fields (in the Soong build the latter is updated).
- Fix this, as these fields are subsequently used in apex/androidmk.go and in apex/builder/go
- To find out what Soong build puts there, run:
- vctx := visitorContext{handleSpecialLibs: !android.Bool(a.properties.Ignore_system_library_special_case)}
- ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
- return a.depVisitor(&vctx, ctx, child, parent)
- })
- vctx.normalizeFileInfo()
- */
-
+ // filesInfo is not set in mixed mode, because all information about the
+ // apex's contents should completely come from the Starlark providers.
+ //
+ // Prevent accidental writes to filesInfo in the earlier parts Soong by
+ // asserting it to be nil.
+ if a.filesInfo != nil {
+ panic(fmt.Errorf("internal error: filesInfo must be nil for an apex handled by Bazel."))
+ }
}
func (a *apexBundle) setCompression(ctx android.ModuleContext) {
@@ -2475,6 +2480,9 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
case *java.Library, *java.SdkLibrary:
af := apexFileForJavaModule(ctx, child.(javaModule))
vctx.filesInfo = append(vctx.filesInfo, af)
+ if profileAf := apexFileForJavaModuleProfile(ctx, child.(javaModule)); profileAf != nil {
+ vctx.filesInfo = append(vctx.filesInfo, *profileAf)
+ }
return true // track transitive dependencies
default:
ctx.PropertyErrorf("systemserverclasspath_fragments",
@@ -3105,9 +3113,9 @@ func isStaticExecutableAllowed(apex string, exec string) bool {
// Collect information for opening IDE project files in java/jdeps.go.
func (a *apexBundle) IDEInfo(dpInfo *android.IdeInfo) {
- dpInfo.Deps = append(dpInfo.Deps, a.overridableProperties.Java_libs...)
- dpInfo.Deps = append(dpInfo.Deps, a.overridableProperties.Bootclasspath_fragments...)
- dpInfo.Deps = append(dpInfo.Deps, a.overridableProperties.Systemserverclasspath_fragments...)
+ dpInfo.Deps = append(dpInfo.Deps, a.properties.Java_libs...)
+ dpInfo.Deps = append(dpInfo.Deps, a.properties.Bootclasspath_fragments...)
+ dpInfo.Deps = append(dpInfo.Deps, a.properties.Systemserverclasspath_fragments...)
dpInfo.Paths = append(dpInfo.Paths, a.modulePaths...)
}
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index 6faed7011..158194937 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -55,17 +55,17 @@ var (
touch ${out};
else
echo -e "\n******************************";
- echo "ERROR: go/apex-allowed-deps-error";
+ echo "ERROR: go/apex-allowed-deps-error contains more information";
echo "******************************";
echo "Detected changes to allowed dependencies in updatable modules.";
echo "To fix and update packages/modules/common/build/allowed_deps.txt, please run:";
echo -e "$$ (croot && packages/modules/common/build/update-apex-allowed-deps.sh)\n";
echo "When submitting the generated CL, you must include the following information";
echo "in the commit message if you are adding a new dependency:";
- echo "Apex-Size-Increase:";
- echo "Previous-Platform-Support:";
- echo "Aosp-First:";
- echo "Test-Info:";
+ echo "Apex-Size-Increase: Expected binary size increase for affected APEXes (or the size of the .jar / .so file of the new library)";
+ echo "Previous-Platform-Support: Are the maintainers of the new dependency committed to supporting previous platform releases?";
+ echo "Aosp-First: Is the new dependency being developed AOSP-first or internal?";
+ echo "Test-Info: What’s the testing strategy for the new dependency? Does it have its own tests, and are you adding integration tests? How/when are the tests run?";
echo "You do not need OWNERS approval to submit the change, but mainline-modularization@";
echo "will periodically review additions and may require changes.";
echo -e "******************************\n";
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 31e848e42..c94bbbb32 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -784,6 +784,43 @@ func TestApexManifestMinSdkVersion(t *testing.T) {
}
}
+func TestFileContexts(t *testing.T) {
+ for _, useFileContextsAsIs := range []bool{true, false} {
+ prop := ""
+ if useFileContextsAsIs {
+ prop = "use_file_contexts_as_is: true,\n"
+ }
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ file_contexts: "file_contexts",
+ updatable: false,
+ vendor: true,
+ `+prop+`
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `, withFiles(map[string][]byte{
+ "file_contexts": nil,
+ }))
+
+ rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("file_contexts")
+ forceLabellingCommand := "apex_manifest\\\\.pb u:object_r:system_file:s0"
+ if useFileContextsAsIs {
+ android.AssertStringDoesNotContain(t, "should force-label",
+ rule.RuleParams.Command, forceLabellingCommand)
+ } else {
+ android.AssertStringDoesContain(t, "shouldn't force-label",
+ rule.RuleParams.Command, forceLabellingCommand)
+ }
+ }
+}
+
func TestBasicZipApex(t *testing.T) {
ctx := testApex(t, `
apex {
@@ -2128,6 +2165,34 @@ func TestApexMinSdkVersion_ErrorIfIncompatibleVersion(t *testing.T) {
min_sdk_version: "30",
}
`)
+
+ // Skip check for modules compiling against core API surface
+ testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ java_libs: ["libfoo"],
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "libfoo",
+ srcs: ["Foo.java"],
+ apex_available: [
+ "myapex",
+ ],
+ // Compile against core API surface
+ sdk_version: "core_current",
+ min_sdk_version: "30",
+ }
+ `)
+
}
func TestApexMinSdkVersion_Okay(t *testing.T) {
@@ -3484,14 +3549,14 @@ func getFiles(t *testing.T, ctx *android.TestContext, moduleName, variant string
return ret
}
-func ensureExactContents(t *testing.T, ctx *android.TestContext, moduleName, variant string, files []string) {
+func assertFileListEquals(t *testing.T, expectedFiles []string, actualFiles []fileInApex) {
t.Helper()
var failed bool
var surplus []string
filesMatched := make(map[string]bool)
- for _, file := range getFiles(t, ctx, moduleName, variant) {
+ for _, file := range actualFiles {
matchFound := false
- for _, expected := range files {
+ for _, expected := range expectedFiles {
if file.match(expected) {
matchFound = true
filesMatched[expected] = true
@@ -3509,9 +3574,9 @@ func ensureExactContents(t *testing.T, ctx *android.TestContext, moduleName, var
failed = true
}
- if len(files) > len(filesMatched) {
+ if len(expectedFiles) > len(filesMatched) {
var missing []string
- for _, expected := range files {
+ for _, expected := range expectedFiles {
if !filesMatched[expected] {
missing = append(missing, expected)
}
@@ -3525,6 +3590,32 @@ func ensureExactContents(t *testing.T, ctx *android.TestContext, moduleName, var
}
}
+func ensureExactContents(t *testing.T, ctx *android.TestContext, moduleName, variant string, files []string) {
+ assertFileListEquals(t, files, getFiles(t, ctx, moduleName, variant))
+}
+
+func ensureExactDeapexedContents(t *testing.T, ctx *android.TestContext, moduleName string, variant string, files []string) {
+ deapexer := ctx.ModuleForTests(moduleName+".deapexer", variant).Rule("deapexer")
+ outputs := make([]string, 0, len(deapexer.ImplicitOutputs)+1)
+ if deapexer.Output != nil {
+ outputs = append(outputs, deapexer.Output.String())
+ }
+ for _, output := range deapexer.ImplicitOutputs {
+ outputs = append(outputs, output.String())
+ }
+ actualFiles := make([]fileInApex, 0, len(outputs))
+ for _, output := range outputs {
+ dir := "/deapexer/"
+ pos := strings.LastIndex(output, dir)
+ if pos == -1 {
+ t.Fatal("Unknown deapexer output ", output)
+ }
+ path := output[pos+len(dir):]
+ actualFiles = append(actualFiles, fileInApex{path: path, src: "", isLink: false})
+ }
+ assertFileListEquals(t, files, actualFiles)
+}
+
func TestVndkApexCurrent(t *testing.T) {
commonFiles := []string{
"lib/libc++.so",
@@ -3806,11 +3897,9 @@ func TestVndkApexNameRule(t *testing.T) {
}`+vndkLibrariesTxtFiles("28", "current"))
assertApexName := func(expected, moduleName string) {
- bundle := ctx.ModuleForTests(moduleName, "android_common_image").Module().(*apexBundle)
- actual := proptools.String(bundle.properties.Apex_name)
- if !reflect.DeepEqual(actual, expected) {
- t.Errorf("Got '%v', expected '%v'", actual, expected)
- }
+ module := ctx.ModuleForTests(moduleName, "android_common_image")
+ apexManifestRule := module.Rule("apexManifestRule")
+ ensureContains(t, apexManifestRule.Args["opt"], "-v name "+expected)
}
assertApexName("com.android.vndk.v29", "com.android.vndk.current")
@@ -4107,57 +4196,11 @@ func TestDependenciesInApexManifest(t *testing.T) {
ensureListEmpty(t, requireNativeLibs)
}
-func TestApexName(t *testing.T) {
- ctx := testApex(t, `
- apex {
- name: "myapex",
- key: "myapex.key",
- apex_name: "com.android.myapex",
- native_shared_libs: ["mylib"],
- updatable: false,
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
- cc_library {
- name: "mylib",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- apex_available: [
- "//apex_available:platform",
- "myapex",
- ],
- }
- `)
-
- module := ctx.ModuleForTests("myapex", "android_common_com.android.myapex_image")
- apexManifestRule := module.Rule("apexManifestRule")
- ensureContains(t, apexManifestRule.Args["opt"], "-v name com.android.myapex")
- apexRule := module.Rule("apexRule")
- ensureContains(t, apexRule.Args["opt_flags"], "--do_not_check_keyname")
-
- apexBundle := module.Module().(*apexBundle)
- data := android.AndroidMkDataForTest(t, ctx, apexBundle)
- name := apexBundle.BaseModuleName()
- prefix := "TARGET_"
- var builder strings.Builder
- data.Custom(&builder, name, prefix, "", data)
- androidMk := builder.String()
- ensureContains(t, androidMk, "LOCAL_MODULE := mylib.myapex\n")
- ensureNotContains(t, androidMk, "LOCAL_MODULE := mylib.com.android.myapex\n")
-}
-
func TestOverrideApexManifestDefaultVersion(t *testing.T) {
ctx := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
- apex_name: "com.android.myapex",
native_shared_libs: ["mylib"],
updatable: false,
}
@@ -4182,7 +4225,7 @@ func TestOverrideApexManifestDefaultVersion(t *testing.T) {
"OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION": "1234",
}))
- module := ctx.ModuleForTests("myapex", "android_common_com.android.myapex_image")
+ module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
apexManifestRule := module.Rule("apexManifestRule")
ensureContains(t, apexManifestRule.Args["default_version"], "1234")
}
@@ -6316,9 +6359,6 @@ func TestOverrideApex(t *testing.T) {
apps: ["app"],
bpfs: ["bpf"],
prebuilts: ["myetc"],
- bootclasspath_fragments: ["mybootclasspath_fragment"],
- systemserverclasspath_fragments: ["mysystemserverclasspath_fragment"],
- java_libs: ["myjava_library"],
overrides: ["oldapex"],
updatable: false,
}
@@ -6329,9 +6369,6 @@ func TestOverrideApex(t *testing.T) {
apps: ["override_app"],
bpfs: ["overrideBpf"],
prebuilts: ["override_myetc"],
- bootclasspath_fragments: ["override_bootclasspath_fragment"],
- systemserverclasspath_fragments: ["override_systemserverclasspath_fragment"],
- java_libs: ["override_java_library"],
overrides: ["unknownapex"],
logging_parent: "com.foo.bar",
package_name: "test.overridden.package",
@@ -6390,78 +6427,6 @@ func TestOverrideApex(t *testing.T) {
name: "override_myetc",
src: "override_myprebuilt",
}
-
- java_library {
- name: "bcplib",
- srcs: ["a.java"],
- compile_dex: true,
- apex_available: ["myapex"],
- permitted_packages: ["bcp.lib"],
- }
-
- bootclasspath_fragment {
- name: "mybootclasspath_fragment",
- contents: ["bcplib"],
- apex_available: ["myapex"],
- hidden_api: {
- split_packages: ["*"],
- },
- }
-
- java_library {
- name: "override_bcplib",
- srcs: ["a.java"],
- compile_dex: true,
- apex_available: ["myapex"],
- permitted_packages: ["override.bcp.lib"],
- }
-
- bootclasspath_fragment {
- name: "override_bootclasspath_fragment",
- contents: ["override_bcplib"],
- apex_available: ["myapex"],
- hidden_api: {
- split_packages: ["*"],
- },
- }
-
- java_library {
- name: "systemserverlib",
- srcs: ["a.java"],
- apex_available: ["myapex"],
- }
-
- systemserverclasspath_fragment {
- name: "mysystemserverclasspath_fragment",
- standalone_contents: ["systemserverlib"],
- apex_available: ["myapex"],
- }
-
- java_library {
- name: "override_systemserverlib",
- srcs: ["a.java"],
- apex_available: ["myapex"],
- }
-
- systemserverclasspath_fragment {
- name: "override_systemserverclasspath_fragment",
- standalone_contents: ["override_systemserverlib"],
- apex_available: ["myapex"],
- }
-
- java_library {
- name: "myjava_library",
- srcs: ["a.java"],
- compile_dex: true,
- apex_available: ["myapex"],
- }
-
- java_library {
- name: "override_java_library",
- srcs: ["a.java"],
- compile_dex: true,
- apex_available: ["myapex"],
- }
`, withManifestPackageNameOverrides([]string{"myapex:com.android.myapex"}))
originalVariant := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(android.OverridableModule)
@@ -6496,13 +6461,6 @@ func TestOverrideApex(t *testing.T) {
t.Errorf("override_myapex should have logging parent (com.foo.bar), but was %q.", apexBundle.overridableProperties.Logging_parent)
}
- android.AssertArrayString(t, "Bootclasspath_fragments does not match",
- []string{"override_bootclasspath_fragment"}, apexBundle.overridableProperties.Bootclasspath_fragments)
- android.AssertArrayString(t, "Systemserverclasspath_fragments does not match",
- []string{"override_systemserverclasspath_fragment"}, apexBundle.overridableProperties.Systemserverclasspath_fragments)
- android.AssertArrayString(t, "Java_libs does not match",
- []string{"override_java_library"}, apexBundle.overridableProperties.Java_libs)
-
optFlags := apexRule.Args["opt_flags"]
ensureContains(t, optFlags, "--override_apk_package_name test.overridden.package")
ensureContains(t, optFlags, "--pubkey testkey2.avbpubkey")
@@ -6517,18 +6475,12 @@ func TestOverrideApex(t *testing.T) {
ensureContains(t, androidMk, "LOCAL_MODULE := override_app.override_myapex")
ensureContains(t, androidMk, "LOCAL_MODULE := overrideBpf.o.override_myapex")
ensureContains(t, androidMk, "LOCAL_MODULE := apex_manifest.pb.override_myapex")
- ensureContains(t, androidMk, "LOCAL_MODULE := override_bcplib.override_myapex")
- ensureContains(t, androidMk, "LOCAL_MODULE := override_systemserverlib.override_myapex")
- ensureContains(t, androidMk, "LOCAL_MODULE := override_java_library.override_myapex")
ensureContains(t, androidMk, "LOCAL_MODULE_STEM := override_myapex.apex")
ensureContains(t, androidMk, "LOCAL_OVERRIDES_MODULES := unknownapex myapex")
ensureNotContains(t, androidMk, "LOCAL_MODULE := app.myapex")
ensureNotContains(t, androidMk, "LOCAL_MODULE := bpf.myapex")
ensureNotContains(t, androidMk, "LOCAL_MODULE := override_app.myapex")
ensureNotContains(t, androidMk, "LOCAL_MODULE := apex_manifest.pb.myapex")
- ensureNotContains(t, androidMk, "LOCAL_MODULE := override_bcplib.myapex")
- ensureNotContains(t, androidMk, "LOCAL_MODULE := override_systemserverlib.myapex")
- ensureNotContains(t, androidMk, "LOCAL_MODULE := override_java_library.pb.myapex")
ensureNotContains(t, androidMk, "LOCAL_MODULE_STEM := myapex.apex")
}
@@ -7144,7 +7096,10 @@ func TestSymlinksFromApexToSystem(t *testing.T) {
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- shared_libs: ["myotherlib"],
+ shared_libs: [
+ "myotherlib",
+ "myotherlib_ext",
+ ],
system_shared_libs: [],
stl: "none",
apex_available: [
@@ -7168,6 +7123,20 @@ func TestSymlinksFromApexToSystem(t *testing.T) {
min_sdk_version: "current",
}
+ cc_library {
+ name: "myotherlib_ext",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ system_ext_specific: true,
+ stl: "none",
+ apex_available: [
+ "myapex",
+ "myapex.updatable",
+ "//apex_available:platform",
+ ],
+ min_sdk_version: "current",
+ }
+
java_library {
name: "myjar",
srcs: ["foo/bar/MyClass.java"],
@@ -7208,12 +7177,15 @@ func TestSymlinksFromApexToSystem(t *testing.T) {
t.Errorf("%q is not found", file)
}
- ensureSymlinkExists := func(t *testing.T, files []fileInApex, file string) {
+ ensureSymlinkExists := func(t *testing.T, files []fileInApex, file string, target string) {
for _, f := range files {
if f.path == file {
if !f.isLink {
t.Errorf("%q is not a symlink", file)
}
+ if f.src != target {
+ t.Errorf("expected symlink target to be %q, got %q", target, f.src)
+ }
return
}
}
@@ -7227,23 +7199,27 @@ func TestSymlinksFromApexToSystem(t *testing.T) {
ensureRealfileExists(t, files, "javalib/myjar.jar")
ensureRealfileExists(t, files, "lib64/mylib.so")
ensureRealfileExists(t, files, "lib64/myotherlib.so")
+ ensureRealfileExists(t, files, "lib64/myotherlib_ext.so")
files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable_image")
ensureRealfileExists(t, files, "javalib/myjar.jar")
ensureRealfileExists(t, files, "lib64/mylib.so")
ensureRealfileExists(t, files, "lib64/myotherlib.so")
+ ensureRealfileExists(t, files, "lib64/myotherlib_ext.so")
// For bundled build, symlink to the system for the non-updatable APEXes only
ctx = testApex(t, bp)
files = getFiles(t, ctx, "myapex", "android_common_myapex_image")
ensureRealfileExists(t, files, "javalib/myjar.jar")
ensureRealfileExists(t, files, "lib64/mylib.so")
- ensureSymlinkExists(t, files, "lib64/myotherlib.so") // this is symlink
+ ensureSymlinkExists(t, files, "lib64/myotherlib.so", "/system/lib64/myotherlib.so") // this is symlink
+ ensureSymlinkExists(t, files, "lib64/myotherlib_ext.so", "/system_ext/lib64/myotherlib_ext.so") // this is symlink
files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable_image")
ensureRealfileExists(t, files, "javalib/myjar.jar")
ensureRealfileExists(t, files, "lib64/mylib.so")
- ensureRealfileExists(t, files, "lib64/myotherlib.so") // this is a real file
+ ensureRealfileExists(t, files, "lib64/myotherlib.so") // this is a real file
+ ensureRealfileExists(t, files, "lib64/myotherlib_ext.so") // this is a real file
}
func TestSymlinksFromApexToSystemRequiredModuleNames(t *testing.T) {
@@ -9561,187 +9537,188 @@ func ensureDoesNotContainRequiredDeps(t *testing.T, ctx *android.TestContext, mo
}
}
-func TestApexStrictUpdtabilityLint(t *testing.T) {
- bpTemplate := `
- apex {
- name: "myapex",
- key: "myapex.key",
- java_libs: ["myjavalib"],
- updatable: %v,
- min_sdk_version: "29",
- }
- apex_key {
- name: "myapex.key",
- }
- java_library {
- name: "myjavalib",
- srcs: ["MyClass.java"],
- apex_available: [ "myapex" ],
- lint: {
- strict_updatability_linting: %v,
- },
- sdk_version: "current",
- min_sdk_version: "29",
- }
- `
- fs := android.MockFS{
- "lint-baseline.xml": nil,
- }
-
- testCases := []struct {
- testCaseName string
- apexUpdatable bool
- javaStrictUpdtabilityLint bool
- lintFileExists bool
- disallowedFlagExpected bool
- }{
- {
- testCaseName: "lint-baseline.xml does not exist, no disallowed flag necessary in lint cmd",
- apexUpdatable: true,
- javaStrictUpdtabilityLint: true,
- lintFileExists: false,
- disallowedFlagExpected: false,
- },
- {
- testCaseName: "non-updatable apex respects strict_updatability of javalib",
- apexUpdatable: false,
- javaStrictUpdtabilityLint: false,
- lintFileExists: true,
- disallowedFlagExpected: false,
- },
- {
- testCaseName: "non-updatable apex respects strict updatability of javalib",
- apexUpdatable: false,
- javaStrictUpdtabilityLint: true,
- lintFileExists: true,
- disallowedFlagExpected: true,
- },
- {
- testCaseName: "updatable apex sets strict updatability of javalib to true",
- apexUpdatable: true,
- javaStrictUpdtabilityLint: false, // will be set to true by mutator
- lintFileExists: true,
- disallowedFlagExpected: true,
- },
- }
-
- for _, testCase := range testCases {
- bp := fmt.Sprintf(bpTemplate, testCase.apexUpdatable, testCase.javaStrictUpdtabilityLint)
- fixtures := []android.FixturePreparer{}
- if testCase.lintFileExists {
- fixtures = append(fixtures, fs.AddToFixture())
- }
-
- result := testApex(t, bp, fixtures...)
- myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
- sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto"))
- disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi")
-
- if disallowedFlagActual != testCase.disallowedFlagExpected {
- t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command)
- }
- }
-}
-
-func TestUpdatabilityLintSkipLibcore(t *testing.T) {
- bp := `
- apex {
- name: "myapex",
- key: "myapex.key",
- java_libs: ["myjavalib"],
- updatable: true,
- min_sdk_version: "29",
- }
- apex_key {
- name: "myapex.key",
- }
- java_library {
- name: "myjavalib",
- srcs: ["MyClass.java"],
- apex_available: [ "myapex" ],
- sdk_version: "current",
- min_sdk_version: "29",
- }
- `
-
- testCases := []struct {
- testCaseName string
- moduleDirectory string
- disallowedFlagExpected bool
- }{
- {
- testCaseName: "lintable module defined outside libcore",
- moduleDirectory: "",
- disallowedFlagExpected: true,
- },
- {
- testCaseName: "lintable module defined in libcore root directory",
- moduleDirectory: "libcore/",
- disallowedFlagExpected: false,
- },
- {
- testCaseName: "lintable module defined in libcore child directory",
- moduleDirectory: "libcore/childdir/",
- disallowedFlagExpected: true,
- },
- }
-
- for _, testCase := range testCases {
- lintFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"lint-baseline.xml", "")
- bpFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"Android.bp", bp)
- result := testApex(t, "", lintFileCreator, bpFileCreator)
- myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
- sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto"))
- cmdFlags := fmt.Sprintf("--baseline %vlint-baseline.xml --disallowed_issues NewApi", testCase.moduleDirectory)
- disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, cmdFlags)
-
- if disallowedFlagActual != testCase.disallowedFlagExpected {
- t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command)
- }
- }
-}
-
-// checks transtive deps of an apex coming from bootclasspath_fragment
-func TestApexStrictUpdtabilityLintBcpFragmentDeps(t *testing.T) {
- bp := `
- apex {
- name: "myapex",
- key: "myapex.key",
- bootclasspath_fragments: ["mybootclasspathfragment"],
- updatable: true,
- min_sdk_version: "29",
- }
- apex_key {
- name: "myapex.key",
- }
- bootclasspath_fragment {
- name: "mybootclasspathfragment",
- contents: ["myjavalib"],
- apex_available: ["myapex"],
- hidden_api: {
- split_packages: ["*"],
- },
- }
- java_library {
- name: "myjavalib",
- srcs: ["MyClass.java"],
- apex_available: [ "myapex" ],
- sdk_version: "current",
- min_sdk_version: "29",
- compile_dex: true,
- }
- `
- fs := android.MockFS{
- "lint-baseline.xml": nil,
- }
-
- result := testApex(t, bp, dexpreopt.FixtureSetApexBootJars("myapex:myjavalib"), fs.AddToFixture())
- myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
- sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto"))
- if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi") {
- t.Errorf("Strict updabality lint missing in myjavalib coming from bootclasspath_fragment mybootclasspath-fragment\nActual lint cmd: %v", *sboxProto.Commands[0].Command)
- }
-}
+// TODO(b/193460475): Re-enable this test
+//func TestApexStrictUpdtabilityLint(t *testing.T) {
+// bpTemplate := `
+// apex {
+// name: "myapex",
+// key: "myapex.key",
+// java_libs: ["myjavalib"],
+// updatable: %v,
+// min_sdk_version: "29",
+// }
+// apex_key {
+// name: "myapex.key",
+// }
+// java_library {
+// name: "myjavalib",
+// srcs: ["MyClass.java"],
+// apex_available: [ "myapex" ],
+// lint: {
+// strict_updatability_linting: %v,
+// },
+// sdk_version: "current",
+// min_sdk_version: "29",
+// }
+// `
+// fs := android.MockFS{
+// "lint-baseline.xml": nil,
+// }
+//
+// testCases := []struct {
+// testCaseName string
+// apexUpdatable bool
+// javaStrictUpdtabilityLint bool
+// lintFileExists bool
+// disallowedFlagExpected bool
+// }{
+// {
+// testCaseName: "lint-baseline.xml does not exist, no disallowed flag necessary in lint cmd",
+// apexUpdatable: true,
+// javaStrictUpdtabilityLint: true,
+// lintFileExists: false,
+// disallowedFlagExpected: false,
+// },
+// {
+// testCaseName: "non-updatable apex respects strict_updatability of javalib",
+// apexUpdatable: false,
+// javaStrictUpdtabilityLint: false,
+// lintFileExists: true,
+// disallowedFlagExpected: false,
+// },
+// {
+// testCaseName: "non-updatable apex respects strict updatability of javalib",
+// apexUpdatable: false,
+// javaStrictUpdtabilityLint: true,
+// lintFileExists: true,
+// disallowedFlagExpected: true,
+// },
+// {
+// testCaseName: "updatable apex sets strict updatability of javalib to true",
+// apexUpdatable: true,
+// javaStrictUpdtabilityLint: false, // will be set to true by mutator
+// lintFileExists: true,
+// disallowedFlagExpected: true,
+// },
+// }
+//
+// for _, testCase := range testCases {
+// bp := fmt.Sprintf(bpTemplate, testCase.apexUpdatable, testCase.javaStrictUpdtabilityLint)
+// fixtures := []android.FixturePreparer{}
+// if testCase.lintFileExists {
+// fixtures = append(fixtures, fs.AddToFixture())
+// }
+//
+// result := testApex(t, bp, fixtures...)
+// myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
+// sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto"))
+// disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi")
+//
+// if disallowedFlagActual != testCase.disallowedFlagExpected {
+// t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command)
+// }
+// }
+//}
+//
+//func TestUpdatabilityLintSkipLibcore(t *testing.T) {
+// bp := `
+// apex {
+// name: "myapex",
+// key: "myapex.key",
+// java_libs: ["myjavalib"],
+// updatable: true,
+// min_sdk_version: "29",
+// }
+// apex_key {
+// name: "myapex.key",
+// }
+// java_library {
+// name: "myjavalib",
+// srcs: ["MyClass.java"],
+// apex_available: [ "myapex" ],
+// sdk_version: "current",
+// min_sdk_version: "29",
+// }
+// `
+//
+// testCases := []struct {
+// testCaseName string
+// moduleDirectory string
+// disallowedFlagExpected bool
+// }{
+// {
+// testCaseName: "lintable module defined outside libcore",
+// moduleDirectory: "",
+// disallowedFlagExpected: true,
+// },
+// {
+// testCaseName: "lintable module defined in libcore root directory",
+// moduleDirectory: "libcore/",
+// disallowedFlagExpected: false,
+// },
+// {
+// testCaseName: "lintable module defined in libcore child directory",
+// moduleDirectory: "libcore/childdir/",
+// disallowedFlagExpected: true,
+// },
+// }
+//
+// for _, testCase := range testCases {
+// lintFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"lint-baseline.xml", "")
+// bpFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"Android.bp", bp)
+// result := testApex(t, "", lintFileCreator, bpFileCreator)
+// myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
+// sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto"))
+// cmdFlags := fmt.Sprintf("--baseline %vlint-baseline.xml --disallowed_issues NewApi", testCase.moduleDirectory)
+// disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, cmdFlags)
+//
+// if disallowedFlagActual != testCase.disallowedFlagExpected {
+// t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command)
+// }
+// }
+//}
+//
+//// checks transtive deps of an apex coming from bootclasspath_fragment
+//func TestApexStrictUpdtabilityLintBcpFragmentDeps(t *testing.T) {
+// bp := `
+// apex {
+// name: "myapex",
+// key: "myapex.key",
+// bootclasspath_fragments: ["mybootclasspathfragment"],
+// updatable: true,
+// min_sdk_version: "29",
+// }
+// apex_key {
+// name: "myapex.key",
+// }
+// bootclasspath_fragment {
+// name: "mybootclasspathfragment",
+// contents: ["myjavalib"],
+// apex_available: ["myapex"],
+// hidden_api: {
+// split_packages: ["*"],
+// },
+// }
+// java_library {
+// name: "myjavalib",
+// srcs: ["MyClass.java"],
+// apex_available: [ "myapex" ],
+// sdk_version: "current",
+// min_sdk_version: "29",
+// compile_dex: true,
+// }
+// `
+// fs := android.MockFS{
+// "lint-baseline.xml": nil,
+// }
+//
+// result := testApex(t, bp, dexpreopt.FixtureSetApexBootJars("myapex:myjavalib"), fs.AddToFixture())
+// myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
+// sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto"))
+// if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi") {
+// t.Errorf("Strict updabality lint missing in myjavalib coming from bootclasspath_fragment mybootclasspath-fragment\nActual lint cmd: %v", *sboxProto.Commands[0].Command)
+// }
+//}
// updatable apexes should propagate updatable=true to its apps
func TestUpdatableApexEnforcesAppUpdatability(t *testing.T) {
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index af4fd9f27..2ddfd0305 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -530,9 +530,8 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) {
java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"),
).RunTest(t)
- ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+ ensureExactDeapexedContents(t, result.TestContext, "com.android.art", "android_common", []string{
"etc/boot-image.prof",
- "etc/classpaths/bootclasspath.pb",
"javalib/arm/boot.art",
"javalib/arm/boot.oat",
"javalib/arm/boot.vdex",
@@ -592,9 +591,8 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) {
java.FixtureSetBootImageInstallDirOnDevice("art", "system/framework"),
).RunTest(t)
- ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+ ensureExactDeapexedContents(t, result.TestContext, "com.android.art", "android_common", []string{
"etc/boot-image.prof",
- "etc/classpaths/bootclasspath.pb",
"javalib/bar.jar",
"javalib/foo.jar",
})
diff --git a/apex/bp2build.go b/apex/bp2build.go
index d28f5122e..a3dda83b1 100644
--- a/apex/bp2build.go
+++ b/apex/bp2build.go
@@ -15,16 +15,22 @@ package apex
import (
"android/soong/android"
+ "encoding/json"
"strings"
)
// This file contains the bp2build integration for the apex package.
// Export constants as Starlark using bp2build to Bazel.
-func BazelApexToolchainVars() string {
+func BazelApexToolchainVars() (string, error) {
+ marshalled, err := json.Marshal(apexAvailBaseline)
+ if err != nil {
+ return "", err
+ }
content := []string{
"# GENERATED BY SOONG. DO NOT EDIT.",
"default_manifest_version = " + android.DefaultUpdatableModuleVersion, // constants.go is different in every branch.
+ "apex_available_baseline = json.decode('''" + string(marshalled) + "''')",
}
- return strings.Join(content, "\n")
+ return strings.Join(content, "\n"), nil
}
diff --git a/apex/builder.go b/apex/builder.go
index 4331d3ec2..ee6c473bd 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -241,10 +241,11 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs,
provideNativeLibs = android.SortedUniqueStrings(provideNativeLibs)
requireNativeLibs = android.SortedUniqueStrings(android.RemoveListFromList(requireNativeLibs, provideNativeLibs))
- // APEX name can be overridden
+ // VNDK APEX name is determined at runtime, so update "name" in apex_manifest
optCommands := []string{}
- if a.properties.Apex_name != nil {
- optCommands = append(optCommands, "-v name "+*a.properties.Apex_name)
+ if a.vndkApex {
+ apexName := vndkApexNamePrefix + a.vndkVersion(ctx.DeviceConfig())
+ optCommands = append(optCommands, "-v name "+apexName)
}
// Collect jniLibs. Notice that a.filesInfo is already sorted
@@ -332,6 +333,8 @@ func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.Output
ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", fileContexts.String())
}
+ useFileContextsAsIs := proptools.Bool(a.properties.Use_file_contexts_as_is)
+
output := android.PathForModuleOut(ctx, "file_contexts")
rule := android.NewRuleBuilder(pctx, ctx)
@@ -343,9 +346,11 @@ func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.Output
rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
// new line
rule.Command().Text("echo").Text(">>").Output(output)
- // force-label /apex_manifest.pb and / as system_file so that apexd can read them
- rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output)
- rule.Command().Text("echo").Flag("/ u:object_r:system_file:s0").Text(">>").Output(output)
+ if !useFileContextsAsIs {
+ // force-label /apex_manifest.pb and / as system_file so that apexd can read them
+ rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output)
+ rule.Command().Text("echo").Flag("/ u:object_r:system_file:s0").Text(">>").Output(output)
+ }
case flattenedApex:
// For flattened apexes, install path should be prepended.
// File_contexts file should be emiited to make via LOCAL_FILE_CONTEXTS
@@ -358,9 +363,11 @@ func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.Output
rule.Command().Text("awk").Text(`'/object_r/{printf("` + apexPath + `%s\n", $0)}'`).Input(fileContexts).Text(">").Output(output)
// new line
rule.Command().Text("echo").Text(">>").Output(output)
- // force-label /apex_manifest.pb and / as system_file so that apexd can read them
- rule.Command().Text("echo").Flag(apexPath + `/apex_manifest\\.pb u:object_r:system_file:s0`).Text(">>").Output(output)
- rule.Command().Text("echo").Flag(apexPath + "/ u:object_r:system_file:s0").Text(">>").Output(output)
+ if !useFileContextsAsIs {
+ // force-label /apex_manifest.pb and / as system_file so that apexd can read them
+ rule.Command().Text("echo").Flag(apexPath + `/apex_manifest\\.pb u:object_r:system_file:s0`).Text(">>").Output(output)
+ rule.Command().Text("echo").Flag(apexPath + "/ u:object_r:system_file:s0").Text(">>").Output(output)
+ }
default:
panic(fmt.Errorf("unsupported type %v", a.properties.ApexType))
}
@@ -445,7 +452,7 @@ func markManifestTestOnly(ctx android.ModuleContext, androidManifestFile android
func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
apexType := a.properties.ApexType
suffix := apexType.suffix()
- apexName := proptools.StringDefault(a.properties.Apex_name, a.BaseModuleName())
+ apexName := a.BaseModuleName()
////////////////////////////////////////////////////////////////////////////////////////////
// Step 1: copy built files to appropriate directories under the image directory
@@ -454,26 +461,13 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
installSymbolFiles := (!ctx.Config().KatiEnabled() || a.ExportedToMake()) && a.installable()
- // b/140136207. When there are overriding APEXes for a VNDK APEX, the symbols file for the overridden
- // APEX and the overriding APEX will have the same installation paths at /apex/com.android.vndk.v<ver>
- // as their apexName will be the same. To avoid the path conflicts, skip installing the symbol files
- // for the overriding VNDK APEXes.
- if a.vndkApex && len(a.overridableProperties.Overrides) > 0 {
- installSymbolFiles = false
- }
-
- // Avoid creating duplicate build rules for multi-installed APEXes.
- if proptools.BoolDefault(a.properties.Multi_install_skip_symbol_files, false) {
- installSymbolFiles = false
-
- }
// set of dependency module:location mappings
installMapSet := make(map[string]bool)
// TODO(jiyong): use the RuleBuilder
var copyCommands []string
var implicitInputs []android.Path
- pathWhenActivated := android.PathForModuleInPartitionInstall(ctx, "apex", apexName)
+ apexDir := android.PathForModuleInPartitionInstall(ctx, "apex", apexName)
for _, fi := range a.filesInfo {
destPath := imageDir.Join(ctx, fi.path()).String()
// Prepare the destination path
@@ -488,8 +482,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
// Copy the built file to the directory. But if the symlink optimization is turned
// on, place a symlink to the corresponding file in /system partition instead.
if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
- // TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here
- pathOnDevice := filepath.Join("/system", fi.path())
+ pathOnDevice := filepath.Join("/", fi.partition, fi.path())
copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath)
} else {
// Copy the file into APEX
@@ -503,12 +496,12 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
fmt.Sprintf("unzip -qDD -d %s %s", destPathDir,
fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs().String()))
if installSymbolFiles {
- installedPath = ctx.InstallFileWithExtraFilesZip(pathWhenActivated.Join(ctx, fi.installDir),
+ installedPath = ctx.InstallFileWithExtraFilesZip(apexDir.Join(ctx, fi.installDir),
fi.stem(), fi.builtFile, fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs())
}
} else {
if installSymbolFiles {
- installedPath = ctx.InstallFile(pathWhenActivated.Join(ctx, fi.installDir), fi.stem(), fi.builtFile)
+ installedPath = ctx.InstallFile(apexDir.Join(ctx, fi.installDir), fi.stem(), fi.builtFile)
}
}
implicitInputs = append(implicitInputs, fi.builtFile)
@@ -522,7 +515,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
symlinkDest := imageDir.Join(ctx, symlinkPath).String()
copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest)
if installSymbolFiles {
- installedSymlink := ctx.InstallSymlink(pathWhenActivated.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath)
+ installedSymlink := ctx.InstallSymlink(apexDir.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath)
implicitInputs = append(implicitInputs, installedSymlink)
}
}
@@ -549,14 +542,14 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
}
implicitInputs = append(implicitInputs, a.manifestPbOut)
if installSymbolFiles {
- installedManifest := ctx.InstallFile(pathWhenActivated, "apex_manifest.pb", a.manifestPbOut)
- installedKey := ctx.InstallFile(pathWhenActivated, "apex_pubkey", a.publicKeyFile)
+ installedManifest := ctx.InstallFile(apexDir, "apex_manifest.pb", a.manifestPbOut)
+ installedKey := ctx.InstallFile(apexDir, "apex_pubkey", a.publicKeyFile)
implicitInputs = append(implicitInputs, installedManifest, installedKey)
}
if len(installMapSet) > 0 {
var installs []string
- installs = append(installs, android.SortedStringKeys(installMapSet)...)
+ installs = append(installs, android.SortedKeys(installMapSet)...)
a.SetLicenseInstallMap(installs)
}
@@ -706,12 +699,6 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
optFlags = append(optFlags, "--unsigned_payload")
}
- if a.properties.Apex_name != nil {
- // If apex_name is set, apexer can skip checking if key name matches with
- // apex name. Note that apex_manifest is also mended.
- optFlags = append(optFlags, "--do_not_check_keyname")
- }
-
if moduleMinSdkVersion == android.SdkVersion_Android10 {
implicitInputs = append(implicitInputs, a.manifestJsonOut)
optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String())
@@ -959,8 +946,7 @@ func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) {
dir := filepath.Join("apex", bundleName, fi.installDir)
installDir := android.PathForModuleInstall(ctx, dir)
if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
- // TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here
- pathOnDevice := filepath.Join("/system", fi.path())
+ pathOnDevice := filepath.Join("/", fi.partition, fi.path())
installedSymlinks = append(installedSymlinks,
ctx.InstallAbsoluteSymlink(installDir, fi.stem(), pathOnDevice))
} else {
@@ -1018,7 +1004,7 @@ func (a *apexBundle) getOverrideManifestPackageName(ctx android.ModuleContext) s
if a.vndkApex {
overrideName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(vndkApexName)
if overridden {
- return strings.Replace(*a.properties.Apex_name, vndkApexName, overrideName, 1)
+ return overrideName + ".v" + a.vndkVersion(ctx.DeviceConfig())
}
return ""
}
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
index d03766448..f94e50f4f 100644
--- a/apex/systemserver_classpath_fragment_test.go
+++ b/apex/systemserver_classpath_fragment_test.go
@@ -15,10 +15,11 @@
package apex
import (
- "android/soong/dexpreopt"
+ "strings"
"testing"
"android/soong/android"
+ "android/soong/dexpreopt"
"android/soong/java"
)
@@ -31,7 +32,7 @@ func TestSystemserverclasspathFragmentContents(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForTestWithSystemserverclasspathFragment,
prepareForTestWithMyapex,
- dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"),
+ dexpreopt.FixtureSetApexSystemServerJars("myapex:foo", "myapex:bar", "myapex:baz"),
).RunTestWithBp(t, `
apex {
name: "myapex",
@@ -57,10 +58,36 @@ func TestSystemserverclasspathFragmentContents(t *testing.T) {
],
}
+ java_library {
+ name: "bar",
+ srcs: ["c.java"],
+ installable: true,
+ dex_preopt: {
+ profile: "bar-art-profile",
+ },
+ apex_available: [
+ "myapex",
+ ],
+ }
+
+ java_library {
+ name: "baz",
+ srcs: ["d.java"],
+ installable: true,
+ dex_preopt: {
+ profile_guided: true, // ignored
+ },
+ apex_available: [
+ "myapex",
+ ],
+ }
+
systemserverclasspath_fragment {
name: "mysystemserverclasspathfragment",
contents: [
"foo",
+ "bar",
+ "baz",
],
apex_available: [
"myapex",
@@ -68,15 +95,24 @@ func TestSystemserverclasspathFragmentContents(t *testing.T) {
}
`)
- ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+ ctx := result.TestContext
+
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
"etc/classpaths/systemserverclasspath.pb",
"javalib/foo.jar",
+ "javalib/bar.jar",
+ "javalib/bar.jar.prof",
+ "javalib/baz.jar",
})
- java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+ java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex_image", []string{
`myapex.key`,
`mysystemserverclasspathfragment`,
})
+
+ assertProfileGuided(t, ctx, "foo", "android_common_apex10000", false)
+ assertProfileGuided(t, ctx, "bar", "android_common_apex10000", true)
+ assertProfileGuided(t, ctx, "baz", "android_common_apex10000", false)
}
func TestSystemserverclasspathFragmentNoGeneratedProto(t *testing.T) {
@@ -186,7 +222,7 @@ func TestPrebuiltSystemserverclasspathFragmentContents(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForTestWithSystemserverclasspathFragment,
prepareForTestWithMyapex,
- dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"),
+ dexpreopt.FixtureSetApexSystemServerJars("myapex:foo", "myapex:bar"),
).RunTestWithBp(t, `
prebuilt_apex {
name: "myapex",
@@ -209,11 +245,23 @@ func TestPrebuiltSystemserverclasspathFragmentContents(t *testing.T) {
],
}
+ java_import {
+ name: "bar",
+ jars: ["bar.jar"],
+ dex_preopt: {
+ profile_guided: true,
+ },
+ apex_available: [
+ "myapex",
+ ],
+ }
+
prebuilt_systemserverclasspath_fragment {
name: "mysystemserverclasspathfragment",
prefer: true,
contents: [
"foo",
+ "bar",
],
apex_available: [
"myapex",
@@ -221,22 +269,34 @@ func TestPrebuiltSystemserverclasspathFragmentContents(t *testing.T) {
}
`)
- java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex", []string{
+ ctx := result.TestContext
+
+ java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{
`myapex.apex.selector`,
`prebuilt_mysystemserverclasspathfragment`,
})
- java.CheckModuleDependencies(t, result.TestContext, "mysystemserverclasspathfragment", "android_common_myapex", []string{
+ java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_myapex", []string{
`myapex.deapexer`,
+ `prebuilt_bar`,
`prebuilt_foo`,
})
+
+ ensureExactDeapexedContents(t, ctx, "myapex", "android_common", []string{
+ "javalib/foo.jar",
+ "javalib/bar.jar",
+ "javalib/bar.jar.prof",
+ })
+
+ assertProfileGuided(t, ctx, "foo", "android_common_myapex", false)
+ assertProfileGuided(t, ctx, "bar", "android_common_myapex", true)
}
func TestSystemserverclasspathFragmentStandaloneContents(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForTestWithSystemserverclasspathFragment,
prepareForTestWithMyapex,
- dexpreopt.FixtureSetApexStandaloneSystemServerJars("myapex:foo"),
+ dexpreopt.FixtureSetApexStandaloneSystemServerJars("myapex:foo", "myapex:bar", "myapex:baz"),
).RunTestWithBp(t, `
apex {
name: "myapex",
@@ -262,10 +322,36 @@ func TestSystemserverclasspathFragmentStandaloneContents(t *testing.T) {
],
}
+ java_library {
+ name: "bar",
+ srcs: ["c.java"],
+ dex_preopt: {
+ profile: "bar-art-profile",
+ },
+ installable: true,
+ apex_available: [
+ "myapex",
+ ],
+ }
+
+ java_library {
+ name: "baz",
+ srcs: ["d.java"],
+ dex_preopt: {
+ profile_guided: true, // ignored
+ },
+ installable: true,
+ apex_available: [
+ "myapex",
+ ],
+ }
+
systemserverclasspath_fragment {
name: "mysystemserverclasspathfragment",
standalone_contents: [
"foo",
+ "bar",
+ "baz",
],
apex_available: [
"myapex",
@@ -273,17 +359,26 @@ func TestSystemserverclasspathFragmentStandaloneContents(t *testing.T) {
}
`)
- ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+ ctx := result.TestContext
+
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
"etc/classpaths/systemserverclasspath.pb",
"javalib/foo.jar",
+ "javalib/bar.jar",
+ "javalib/bar.jar.prof",
+ "javalib/baz.jar",
})
+
+ assertProfileGuided(t, ctx, "foo", "android_common_apex10000", false)
+ assertProfileGuided(t, ctx, "bar", "android_common_apex10000", true)
+ assertProfileGuided(t, ctx, "baz", "android_common_apex10000", false)
}
func TestPrebuiltStandaloneSystemserverclasspathFragmentContents(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForTestWithSystemserverclasspathFragment,
prepareForTestWithMyapex,
- dexpreopt.FixtureSetApexStandaloneSystemServerJars("myapex:foo"),
+ dexpreopt.FixtureSetApexStandaloneSystemServerJars("myapex:foo", "myapex:bar"),
).RunTestWithBp(t, `
prebuilt_apex {
name: "myapex",
@@ -306,11 +401,23 @@ func TestPrebuiltStandaloneSystemserverclasspathFragmentContents(t *testing.T) {
],
}
+ java_import {
+ name: "bar",
+ jars: ["bar.jar"],
+ dex_preopt: {
+ profile_guided: true,
+ },
+ apex_available: [
+ "myapex",
+ ],
+ }
+
prebuilt_systemserverclasspath_fragment {
name: "mysystemserverclasspathfragment",
prefer: true,
standalone_contents: [
"foo",
+ "bar",
],
apex_available: [
"myapex",
@@ -318,8 +425,28 @@ func TestPrebuiltStandaloneSystemserverclasspathFragmentContents(t *testing.T) {
}
`)
- java.CheckModuleDependencies(t, result.TestContext, "mysystemserverclasspathfragment", "android_common_myapex", []string{
+ ctx := result.TestContext
+
+ java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_myapex", []string{
`myapex.deapexer`,
+ `prebuilt_bar`,
`prebuilt_foo`,
})
+
+ ensureExactDeapexedContents(t, ctx, "myapex", "android_common", []string{
+ "javalib/foo.jar",
+ "javalib/bar.jar",
+ "javalib/bar.jar.prof",
+ })
+
+ assertProfileGuided(t, ctx, "foo", "android_common_myapex", false)
+ assertProfileGuided(t, ctx, "bar", "android_common_myapex", true)
+}
+
+func assertProfileGuided(t *testing.T, ctx *android.TestContext, moduleName string, variant string, expected bool) {
+ dexpreopt := ctx.ModuleForTests(moduleName, variant).Rule("dexpreopt")
+ actual := strings.Contains(dexpreopt.RuleParams.Command, "--profile-file=")
+ if expected != actual {
+ t.Fatalf("Expected profile-guided to be %v, got %v", expected, actual)
+ }
}
diff --git a/apex/vndk.go b/apex/vndk.go
index 80560cf0c..c0be753d1 100644
--- a/apex/vndk.go
+++ b/apex/vndk.go
@@ -65,10 +65,6 @@ func apexVndkMutator(mctx android.TopDownMutatorContext) {
}
vndkVersion := ab.vndkVersion(mctx.DeviceConfig())
-
- // Ensure VNDK APEX mount point is formatted as com.android.vndk.v###
- ab.properties.Apex_name = proptools.StringPtr(vndkApexNamePrefix + vndkVersion)
-
apiLevel, err := android.ApiLevelFromUser(mctx, vndkVersion)
if err != nil {
mctx.PropertyErrorf("vndk_version", "%s", err.Error())
diff --git a/bazel/Android.bp b/bazel/Android.bp
index d11c78b04..4709f5cd3 100644
--- a/bazel/Android.bp
+++ b/bazel/Android.bp
@@ -7,6 +7,7 @@ bootstrap_go_package {
pkgPath: "android/soong/bazel",
srcs: [
"aquery.go",
+ "bazel_proxy.go",
"configurability.go",
"constants.go",
"properties.go",
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 80cf70a43..4d39e8f55 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -22,10 +22,13 @@ import (
"reflect"
"sort"
"strings"
+ "sync"
+ analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
+
+ "github.com/google/blueprint/metrics"
"github.com/google/blueprint/proptools"
"google.golang.org/protobuf/proto"
- analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
)
type artifactId int
@@ -103,7 +106,7 @@ type BuildStatement struct {
Depfile *string
OutputPaths []string
SymlinkPaths []string
- Env []KeyValuePair
+ Env []*analysis_v2_proto.KeyValuePair
Mnemonic string
// Inputs of this build statement, either as unexpanded depsets or expanded
@@ -128,7 +131,7 @@ type aqueryArtifactHandler struct {
// depsetIdToArtifactIdsCache is a memoization of depset flattening, because flattening
// may be an expensive operation.
- depsetHashToArtifactPathsCache map[string][]string
+ depsetHashToArtifactPathsCache sync.Map
// Maps artifact ids to fully expanded paths.
artifactIdToPath map[artifactId]string
}
@@ -141,8 +144,11 @@ var templateActionOverriddenTokens = map[string]string{
"%python_binary%": "python3",
}
-// The file name of py3wrapper.sh, which is used by py_binary targets.
-const py3wrapperFileName = "/py3wrapper.sh"
+const (
+ middlemanMnemonic = "Middleman"
+ // The file name of py3wrapper.sh, which is used by py_binary targets.
+ py3wrapperFileName = "/py3wrapper.sh"
+)
func indexBy[K comparable, V any](values []V, keyFn func(v V) K) map[K]V {
m := map[K]V{}
@@ -152,18 +158,18 @@ func indexBy[K comparable, V any](values []V, keyFn func(v V) K) map[K]V {
return m
}
-func newAqueryHandler(aqueryResult actionGraphContainer) (*aqueryArtifactHandler, error) {
- pathFragments := indexBy(aqueryResult.PathFragments, func(pf pathFragment) pathFragmentId {
- return pf.Id
+func newAqueryHandler(aqueryResult *analysis_v2_proto.ActionGraphContainer) (*aqueryArtifactHandler, error) {
+ pathFragments := indexBy(aqueryResult.PathFragments, func(pf *analysis_v2_proto.PathFragment) pathFragmentId {
+ return pathFragmentId(pf.Id)
})
- artifactIdToPath := map[artifactId]string{}
+ artifactIdToPath := make(map[artifactId]string, len(aqueryResult.Artifacts))
for _, artifact := range aqueryResult.Artifacts {
- artifactPath, err := expandPathFragment(artifact.PathFragmentId, pathFragments)
+ artifactPath, err := expandPathFragment(pathFragmentId(artifact.PathFragmentId), pathFragments)
if err != nil {
return nil, err
}
- artifactIdToPath[artifact.Id] = artifactPath
+ artifactIdToPath[artifactId(artifact.Id)] = artifactPath
}
// Map middleman artifact ContentHash to input artifact depset ID.
@@ -171,23 +177,23 @@ func newAqueryHandler(aqueryResult actionGraphContainer) (*aqueryArtifactHandler
// if we find a middleman action which has inputs [foo, bar], and output [baz_middleman], then,
// for each other action which has input [baz_middleman], we add [foo, bar] to the inputs for
// that action instead.
- middlemanIdToDepsetIds := map[artifactId][]depsetId{}
+ middlemanIdToDepsetIds := map[artifactId][]uint32{}
for _, actionEntry := range aqueryResult.Actions {
- if actionEntry.Mnemonic == "Middleman" {
+ if actionEntry.Mnemonic == middlemanMnemonic {
for _, outputId := range actionEntry.OutputIds {
- middlemanIdToDepsetIds[outputId] = actionEntry.InputDepSetIds
+ middlemanIdToDepsetIds[artifactId(outputId)] = actionEntry.InputDepSetIds
}
}
}
- depsetIdToDepset := indexBy(aqueryResult.DepSetOfFiles, func(d depSetOfFiles) depsetId {
- return d.Id
+ depsetIdToDepset := indexBy(aqueryResult.DepSetOfFiles, func(d *analysis_v2_proto.DepSetOfFiles) depsetId {
+ return depsetId(d.Id)
})
aqueryHandler := aqueryArtifactHandler{
depsetIdToAqueryDepset: map[depsetId]AqueryDepset{},
depsetHashToAqueryDepset: map[string]AqueryDepset{},
- depsetHashToArtifactPathsCache: map[string][]string{},
+ depsetHashToArtifactPathsCache: sync.Map{},
emptyDepsetIds: make(map[depsetId]struct{}, 0),
artifactIdToPath: artifactIdToPath,
}
@@ -205,20 +211,21 @@ func newAqueryHandler(aqueryResult actionGraphContainer) (*aqueryArtifactHandler
// Ensures that the handler's depsetIdToAqueryDepset map contains an entry for the given
// depset.
-func (a *aqueryArtifactHandler) populateDepsetMaps(depset depSetOfFiles, middlemanIdToDepsetIds map[artifactId][]depsetId, depsetIdToDepset map[depsetId]depSetOfFiles) (*AqueryDepset, error) {
- if aqueryDepset, containsDepset := a.depsetIdToAqueryDepset[depset.Id]; containsDepset {
+func (a *aqueryArtifactHandler) populateDepsetMaps(depset *analysis_v2_proto.DepSetOfFiles, middlemanIdToDepsetIds map[artifactId][]uint32, depsetIdToDepset map[depsetId]*analysis_v2_proto.DepSetOfFiles) (*AqueryDepset, error) {
+ if aqueryDepset, containsDepset := a.depsetIdToAqueryDepset[depsetId(depset.Id)]; containsDepset {
return &aqueryDepset, nil
}
transitiveDepsetIds := depset.TransitiveDepSetIds
- var directArtifactPaths []string
- for _, artifactId := range depset.DirectArtifactIds {
- path, pathExists := a.artifactIdToPath[artifactId]
+ directArtifactPaths := make([]string, 0, len(depset.DirectArtifactIds))
+ for _, id := range depset.DirectArtifactIds {
+ aId := artifactId(id)
+ path, pathExists := a.artifactIdToPath[aId]
if !pathExists {
- return nil, fmt.Errorf("undefined input artifactId %d", artifactId)
+ return nil, fmt.Errorf("undefined input artifactId %d", aId)
}
// Filter out any inputs which are universally dropped, and swap middleman
// artifacts with their corresponding depsets.
- if depsetsToUse, isMiddleman := middlemanIdToDepsetIds[artifactId]; isMiddleman {
+ if depsetsToUse, isMiddleman := middlemanIdToDepsetIds[aId]; isMiddleman {
// Swap middleman artifacts with their corresponding depsets and drop the middleman artifacts.
transitiveDepsetIds = append(transitiveDepsetIds, depsetsToUse...)
} else if strings.HasSuffix(path, py3wrapperFileName) ||
@@ -235,8 +242,9 @@ func (a *aqueryArtifactHandler) populateDepsetMaps(depset depSetOfFiles, middlem
}
}
- var childDepsetHashes []string
- for _, childDepsetId := range transitiveDepsetIds {
+ childDepsetHashes := make([]string, 0, len(transitiveDepsetIds))
+ for _, id := range transitiveDepsetIds {
+ childDepsetId := depsetId(id)
childDepset, exists := depsetIdToDepset[childDepsetId]
if !exists {
if _, empty := a.emptyDepsetIds[childDepsetId]; empty {
@@ -254,7 +262,7 @@ func (a *aqueryArtifactHandler) populateDepsetMaps(depset depSetOfFiles, middlem
}
}
if len(directArtifactPaths) == 0 && len(childDepsetHashes) == 0 {
- a.emptyDepsetIds[depset.Id] = struct{}{}
+ a.emptyDepsetIds[depsetId(depset.Id)] = struct{}{}
return nil, nil
}
aqueryDepset := AqueryDepset{
@@ -262,7 +270,7 @@ func (a *aqueryArtifactHandler) populateDepsetMaps(depset depSetOfFiles, middlem
DirectArtifacts: directArtifactPaths,
TransitiveDepSetHashes: childDepsetHashes,
}
- a.depsetIdToAqueryDepset[depset.Id] = aqueryDepset
+ a.depsetIdToAqueryDepset[depsetId(depset.Id)] = aqueryDepset
a.depsetHashToAqueryDepset[aqueryDepset.ContentHash] = aqueryDepset
return &aqueryDepset, nil
}
@@ -271,10 +279,11 @@ func (a *aqueryArtifactHandler) populateDepsetMaps(depset depSetOfFiles, middlem
// input paths contained in these depsets.
// This is a potentially expensive operation, and should not be invoked except
// for actions which need specialized input handling.
-func (a *aqueryArtifactHandler) getInputPaths(depsetIds []depsetId) ([]string, error) {
+func (a *aqueryArtifactHandler) getInputPaths(depsetIds []uint32) ([]string, error) {
var inputPaths []string
- for _, inputDepSetId := range depsetIds {
+ for _, id := range depsetIds {
+ inputDepSetId := depsetId(id)
depset := a.depsetIdToAqueryDepset[inputDepSetId]
inputArtifacts, err := a.artifactPathsFromDepsetHash(depset.ContentHash)
if err != nil {
@@ -289,8 +298,8 @@ func (a *aqueryArtifactHandler) getInputPaths(depsetIds []depsetId) ([]string, e
}
func (a *aqueryArtifactHandler) artifactPathsFromDepsetHash(depsetHash string) ([]string, error) {
- if result, exists := a.depsetHashToArtifactPathsCache[depsetHash]; exists {
- return result, nil
+ if result, exists := a.depsetHashToArtifactPathsCache.Load(depsetHash); exists {
+ return result.([]string), nil
}
if depset, exists := a.depsetHashToAqueryDepset[depsetHash]; exists {
result := depset.DirectArtifacts
@@ -301,7 +310,7 @@ func (a *aqueryArtifactHandler) artifactPathsFromDepsetHash(depsetHash string) (
}
result = append(result, childArtifactIds...)
}
- a.depsetHashToArtifactPathsCache[depsetHash] = result
+ a.depsetHashToArtifactPathsCache.Store(depsetHash, result)
return result, nil
} else {
return nil, fmt.Errorf("undefined input depset hash %s", depsetHash)
@@ -313,148 +322,104 @@ func (a *aqueryArtifactHandler) artifactPathsFromDepsetHash(depsetHash string) (
// action graph, as described by the given action graph json proto.
// BuildStatements are one-to-one with actions in the given action graph, and AqueryDepsets
// are one-to-one with Bazel's depSetOfFiles objects.
-func AqueryBuildStatements(aqueryJsonProto []byte) ([]BuildStatement, []AqueryDepset, error) {
+func AqueryBuildStatements(aqueryJsonProto []byte, eventHandler *metrics.EventHandler) ([]*BuildStatement, []AqueryDepset, error) {
aqueryProto := &analysis_v2_proto.ActionGraphContainer{}
err := proto.Unmarshal(aqueryJsonProto, aqueryProto)
if err != nil {
return nil, nil, err
}
- aqueryResult := actionGraphContainer{}
-
- for _, protoArtifact := range aqueryProto.Artifacts {
- aqueryResult.Artifacts = append(aqueryResult.Artifacts, artifact{artifactId(protoArtifact.Id),
- pathFragmentId(protoArtifact.PathFragmentId)})
- }
-
- for _, protoAction := range aqueryProto.Actions {
- var environmentVariable []KeyValuePair
- var inputDepSetIds []depsetId
- var outputIds []artifactId
- var substitutions []KeyValuePair
- for _, protoEnvironmentVariable := range protoAction.EnvironmentVariables {
- environmentVariable = append(environmentVariable, KeyValuePair{
- protoEnvironmentVariable.Key, protoEnvironmentVariable.Value,
- })
- }
- for _, protoInputDepSetIds := range protoAction.InputDepSetIds {
- inputDepSetIds = append(inputDepSetIds, depsetId(protoInputDepSetIds))
- }
- for _, protoOutputIds := range protoAction.OutputIds {
- outputIds = append(outputIds, artifactId(protoOutputIds))
- }
- for _, protoSubstitutions := range protoAction.Substitutions {
- substitutions = append(substitutions, KeyValuePair{
- protoSubstitutions.Key, protoSubstitutions.Value,
- })
+ var aqueryHandler *aqueryArtifactHandler
+ {
+ eventHandler.Begin("init_handler")
+ defer eventHandler.End("init_handler")
+ aqueryHandler, err = newAqueryHandler(aqueryProto)
+ if err != nil {
+ return nil, nil, err
}
-
- aqueryResult.Actions = append(aqueryResult.Actions,
- action{
- Arguments: protoAction.Arguments,
- EnvironmentVariables: environmentVariable,
- InputDepSetIds: inputDepSetIds,
- Mnemonic: protoAction.Mnemonic,
- OutputIds: outputIds,
- TemplateContent: protoAction.TemplateContent,
- Substitutions: substitutions,
- FileContents: protoAction.FileContents})
}
- for _, protoDepSetOfFiles := range aqueryProto.DepSetOfFiles {
- var directArtifactIds []artifactId
- var transitiveDepSetIds []depsetId
-
- for _, protoDirectArtifactIds := range protoDepSetOfFiles.DirectArtifactIds {
- directArtifactIds = append(directArtifactIds, artifactId(protoDirectArtifactIds))
+ // allocate both length and capacity so each goroutine can write to an index independently without
+ // any need for synchronization for slice access.
+ buildStatements := make([]*BuildStatement, len(aqueryProto.Actions))
+ {
+ eventHandler.Begin("build_statements")
+ defer eventHandler.End("build_statements")
+ wg := sync.WaitGroup{}
+ var errOnce sync.Once
+
+ for i, actionEntry := range aqueryProto.Actions {
+ wg.Add(1)
+ go func(i int, actionEntry *analysis_v2_proto.Action) {
+ buildStatement, aErr := aqueryHandler.actionToBuildStatement(actionEntry)
+ if aErr != nil {
+ errOnce.Do(func() {
+ err = aErr
+ })
+ } else {
+ // set build statement at an index rather than appending such that each goroutine does not
+ // impact other goroutines
+ buildStatements[i] = buildStatement
+ }
+ wg.Done()
+ }(i, actionEntry)
}
- for _, protoTransitiveDepSetIds := range protoDepSetOfFiles.TransitiveDepSetIds {
- transitiveDepSetIds = append(transitiveDepSetIds, depsetId(protoTransitiveDepSetIds))
- }
- aqueryResult.DepSetOfFiles = append(aqueryResult.DepSetOfFiles,
- depSetOfFiles{
- Id: depsetId(protoDepSetOfFiles.Id),
- DirectArtifactIds: directArtifactIds,
- TransitiveDepSetIds: transitiveDepSetIds})
-
+ wg.Wait()
}
-
- for _, protoPathFragments := range aqueryProto.PathFragments {
- aqueryResult.PathFragments = append(aqueryResult.PathFragments,
- pathFragment{
- Id: pathFragmentId(protoPathFragments.Id),
- Label: protoPathFragments.Label,
- ParentId: pathFragmentId(protoPathFragments.ParentId)})
-
- }
- aqueryHandler, err := newAqueryHandler(aqueryResult)
if err != nil {
return nil, nil, err
}
- var buildStatements []BuildStatement
- for _, actionEntry := range aqueryResult.Actions {
- if shouldSkipAction(actionEntry) {
- continue
- }
-
- var buildStatement BuildStatement
- if actionEntry.isSymlinkAction() {
- buildStatement, err = aqueryHandler.symlinkActionBuildStatement(actionEntry)
- } else if actionEntry.isTemplateExpandAction() && len(actionEntry.Arguments) < 1 {
- buildStatement, err = aqueryHandler.templateExpandActionBuildStatement(actionEntry)
- } else if actionEntry.isFileWriteAction() {
- buildStatement, err = aqueryHandler.fileWriteActionBuildStatement(actionEntry)
- } else if actionEntry.isSymlinkTreeAction() {
- buildStatement, err = aqueryHandler.symlinkTreeActionBuildStatement(actionEntry)
- } else if len(actionEntry.Arguments) < 1 {
- return nil, nil, fmt.Errorf("received action with no command: [%s]", actionEntry.Mnemonic)
- } else {
- buildStatement, err = aqueryHandler.normalActionBuildStatement(actionEntry)
- }
-
- if err != nil {
- return nil, nil, err
- }
- buildStatements = append(buildStatements, buildStatement)
- }
-
depsetsByHash := map[string]AqueryDepset{}
- var depsets []AqueryDepset
- for _, aqueryDepset := range aqueryHandler.depsetIdToAqueryDepset {
- if prevEntry, hasKey := depsetsByHash[aqueryDepset.ContentHash]; hasKey {
- // Two depsets collide on hash. Ensure that their contents are identical.
- if !reflect.DeepEqual(aqueryDepset, prevEntry) {
- return nil, nil, fmt.Errorf("two different depsets have the same hash: %v, %v", prevEntry, aqueryDepset)
+ depsets := make([]AqueryDepset, 0, len(aqueryHandler.depsetIdToAqueryDepset))
+ {
+ eventHandler.Begin("depsets")
+ defer eventHandler.End("depsets")
+ for _, aqueryDepset := range aqueryHandler.depsetIdToAqueryDepset {
+ if prevEntry, hasKey := depsetsByHash[aqueryDepset.ContentHash]; hasKey {
+ // Two depsets collide on hash. Ensure that their contents are identical.
+ if !reflect.DeepEqual(aqueryDepset, prevEntry) {
+ return nil, nil, fmt.Errorf("two different depsets have the same hash: %v, %v", prevEntry, aqueryDepset)
+ }
+ } else {
+ depsetsByHash[aqueryDepset.ContentHash] = aqueryDepset
+ depsets = append(depsets, aqueryDepset)
}
- } else {
- depsetsByHash[aqueryDepset.ContentHash] = aqueryDepset
- depsets = append(depsets, aqueryDepset)
}
}
- // Build Statements and depsets must be sorted by their content hash to
- // preserve determinism between builds (this will result in consistent ninja file
- // output). Note they are not sorted by their original IDs nor their Bazel ordering,
- // as Bazel gives nondeterministic ordering / identifiers in aquery responses.
- sort.Slice(buildStatements, func(i, j int) bool {
- // For build statements, compare output lists. In Bazel, each output file
- // may only have one action which generates it, so this will provide
- // a deterministic ordering.
- outputs_i := buildStatements[i].OutputPaths
- outputs_j := buildStatements[j].OutputPaths
- if len(outputs_i) != len(outputs_j) {
- return len(outputs_i) < len(outputs_j)
- }
- if len(outputs_i) == 0 {
- // No outputs for these actions, so compare commands.
- return buildStatements[i].Command < buildStatements[j].Command
- }
- // There may be multiple outputs, but the output ordering is deterministic.
- return outputs_i[0] < outputs_j[0]
+ eventHandler.Do("build_statement_sort", func() {
+ // Build Statements and depsets must be sorted by their content hash to
+ // preserve determinism between builds (this will result in consistent ninja file
+ // output). Note they are not sorted by their original IDs nor their Bazel ordering,
+ // as Bazel gives nondeterministic ordering / identifiers in aquery responses.
+ sort.Slice(buildStatements, func(i, j int) bool {
+ // Sort all nil statements to the end of the slice
+ if buildStatements[i] == nil {
+ return false
+ } else if buildStatements[j] == nil {
+ return true
+ }
+ //For build statements, compare output lists. In Bazel, each output file
+ // may only have one action which generates it, so this will provide
+ // a deterministic ordering.
+ outputs_i := buildStatements[i].OutputPaths
+ outputs_j := buildStatements[j].OutputPaths
+ if len(outputs_i) != len(outputs_j) {
+ return len(outputs_i) < len(outputs_j)
+ }
+ if len(outputs_i) == 0 {
+ // No outputs for these actions, so compare commands.
+ return buildStatements[i].Command < buildStatements[j].Command
+ }
+ // There may be multiple outputs, but the output ordering is deterministic.
+ return outputs_i[0] < outputs_j[0]
+ })
})
- sort.Slice(depsets, func(i, j int) bool {
- return depsets[i].ContentHash < depsets[j].ContentHash
+ eventHandler.Do("depset_sort", func() {
+ sort.Slice(depsets, func(i, j int) bool {
+ return depsets[i].ContentHash < depsets[j].ContentHash
+ })
})
return buildStatements, depsets, nil
}
@@ -473,12 +438,13 @@ func depsetContentHash(directPaths []string, transitiveDepsetHashes []string) st
return fullHash
}
-func (a *aqueryArtifactHandler) depsetContentHashes(inputDepsetIds []depsetId) ([]string, error) {
+func (a *aqueryArtifactHandler) depsetContentHashes(inputDepsetIds []uint32) ([]string, error) {
var hashes []string
- for _, depsetId := range inputDepsetIds {
- if aqueryDepset, exists := a.depsetIdToAqueryDepset[depsetId]; !exists {
- if _, empty := a.emptyDepsetIds[depsetId]; !empty {
- return nil, fmt.Errorf("undefined (not even empty) input depsetId %d", depsetId)
+ for _, id := range inputDepsetIds {
+ dId := depsetId(id)
+ if aqueryDepset, exists := a.depsetIdToAqueryDepset[dId]; !exists {
+ if _, empty := a.emptyDepsetIds[dId]; !empty {
+ return nil, fmt.Errorf("undefined (not even empty) input depsetId %d", dId)
}
} else {
hashes = append(hashes, aqueryDepset.ContentHash)
@@ -487,18 +453,18 @@ func (a *aqueryArtifactHandler) depsetContentHashes(inputDepsetIds []depsetId) (
return hashes, nil
}
-func (a *aqueryArtifactHandler) normalActionBuildStatement(actionEntry action) (BuildStatement, error) {
+func (a *aqueryArtifactHandler) normalActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
command := strings.Join(proptools.ShellEscapeListIncludingSpaces(actionEntry.Arguments), " ")
inputDepsetHashes, err := a.depsetContentHashes(actionEntry.InputDepSetIds)
if err != nil {
- return BuildStatement{}, err
+ return nil, err
}
outputPaths, depfile, err := a.getOutputPaths(actionEntry)
if err != nil {
- return BuildStatement{}, err
+ return nil, err
}
- buildStatement := BuildStatement{
+ buildStatement := &BuildStatement{
Command: command,
Depfile: depfile,
OutputPaths: outputPaths,
@@ -509,13 +475,13 @@ func (a *aqueryArtifactHandler) normalActionBuildStatement(actionEntry action) (
return buildStatement, nil
}
-func (a *aqueryArtifactHandler) templateExpandActionBuildStatement(actionEntry action) (BuildStatement, error) {
+func (a *aqueryArtifactHandler) templateExpandActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
outputPaths, depfile, err := a.getOutputPaths(actionEntry)
if err != nil {
- return BuildStatement{}, err
+ return nil, err
}
if len(outputPaths) != 1 {
- return BuildStatement{}, fmt.Errorf("Expect 1 output to template expand action, got: output %q", outputPaths)
+ return nil, fmt.Errorf("Expect 1 output to template expand action, got: output %q", outputPaths)
}
expandedTemplateContent := expandTemplateContent(actionEntry)
// The expandedTemplateContent is escaped for being used in double quotes and shell unescape,
@@ -527,10 +493,10 @@ func (a *aqueryArtifactHandler) templateExpandActionBuildStatement(actionEntry a
escapeCommandlineArgument(expandedTemplateContent), outputPaths[0])
inputDepsetHashes, err := a.depsetContentHashes(actionEntry.InputDepSetIds)
if err != nil {
- return BuildStatement{}, err
+ return nil, err
}
- buildStatement := BuildStatement{
+ buildStatement := &BuildStatement{
Command: command,
Depfile: depfile,
OutputPaths: outputPaths,
@@ -541,16 +507,16 @@ func (a *aqueryArtifactHandler) templateExpandActionBuildStatement(actionEntry a
return buildStatement, nil
}
-func (a *aqueryArtifactHandler) fileWriteActionBuildStatement(actionEntry action) (BuildStatement, error) {
+func (a *aqueryArtifactHandler) fileWriteActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
outputPaths, _, err := a.getOutputPaths(actionEntry)
var depsetHashes []string
if err == nil {
depsetHashes, err = a.depsetContentHashes(actionEntry.InputDepSetIds)
}
if err != nil {
- return BuildStatement{}, err
+ return nil, err
}
- return BuildStatement{
+ return &BuildStatement{
Depfile: nil,
OutputPaths: outputPaths,
Env: actionEntry.EnvironmentVariables,
@@ -560,20 +526,20 @@ func (a *aqueryArtifactHandler) fileWriteActionBuildStatement(actionEntry action
}, nil
}
-func (a *aqueryArtifactHandler) symlinkTreeActionBuildStatement(actionEntry action) (BuildStatement, error) {
+func (a *aqueryArtifactHandler) symlinkTreeActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
outputPaths, _, err := a.getOutputPaths(actionEntry)
if err != nil {
- return BuildStatement{}, err
+ return nil, err
}
inputPaths, err := a.getInputPaths(actionEntry.InputDepSetIds)
if err != nil {
- return BuildStatement{}, err
+ return nil, err
}
if len(inputPaths) != 1 || len(outputPaths) != 1 {
- return BuildStatement{}, fmt.Errorf("Expect 1 input and 1 output to symlink action, got: input %q, output %q", inputPaths, outputPaths)
+ return nil, fmt.Errorf("Expect 1 input and 1 output to symlink action, got: input %q, output %q", inputPaths, outputPaths)
}
// The actual command is generated in bazelSingleton.GenerateBuildActions
- return BuildStatement{
+ return &BuildStatement{
Depfile: nil,
OutputPaths: outputPaths,
Env: actionEntry.EnvironmentVariables,
@@ -582,18 +548,18 @@ func (a *aqueryArtifactHandler) symlinkTreeActionBuildStatement(actionEntry acti
}, nil
}
-func (a *aqueryArtifactHandler) symlinkActionBuildStatement(actionEntry action) (BuildStatement, error) {
+func (a *aqueryArtifactHandler) symlinkActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
outputPaths, depfile, err := a.getOutputPaths(actionEntry)
if err != nil {
- return BuildStatement{}, err
+ return nil, err
}
inputPaths, err := a.getInputPaths(actionEntry.InputDepSetIds)
if err != nil {
- return BuildStatement{}, err
+ return nil, err
}
if len(inputPaths) != 1 || len(outputPaths) != 1 {
- return BuildStatement{}, fmt.Errorf("Expect 1 input and 1 output to symlink action, got: input %q, output %q", inputPaths, outputPaths)
+ return nil, fmt.Errorf("Expect 1 input and 1 output to symlink action, got: input %q, output %q", inputPaths, outputPaths)
}
out := outputPaths[0]
outDir := proptools.ShellEscapeIncludingSpaces(filepath.Dir(out))
@@ -603,7 +569,7 @@ func (a *aqueryArtifactHandler) symlinkActionBuildStatement(actionEntry action)
command := fmt.Sprintf("mkdir -p %[1]s && rm -f %[2]s && ln -sf %[3]s %[2]s", outDir, out, in)
symlinkPaths := outputPaths[:]
- buildStatement := BuildStatement{
+ buildStatement := &BuildStatement{
Command: command,
Depfile: depfile,
OutputPaths: outputPaths,
@@ -615,9 +581,9 @@ func (a *aqueryArtifactHandler) symlinkActionBuildStatement(actionEntry action)
return buildStatement, nil
}
-func (a *aqueryArtifactHandler) getOutputPaths(actionEntry action) (outputPaths []string, depfile *string, err error) {
+func (a *aqueryArtifactHandler) getOutputPaths(actionEntry *analysis_v2_proto.Action) (outputPaths []string, depfile *string, err error) {
for _, outputId := range actionEntry.OutputIds {
- outputPath, exists := a.artifactIdToPath[outputId]
+ outputPath, exists := a.artifactIdToPath[artifactId(outputId)]
if !exists {
err = fmt.Errorf("undefined outputId %d", outputId)
return
@@ -638,70 +604,69 @@ func (a *aqueryArtifactHandler) getOutputPaths(actionEntry action) (outputPaths
}
// expandTemplateContent substitutes the tokens in a template.
-func expandTemplateContent(actionEntry action) string {
- var replacerString []string
- for _, pair := range actionEntry.Substitutions {
+func expandTemplateContent(actionEntry *analysis_v2_proto.Action) string {
+ replacerString := make([]string, len(actionEntry.Substitutions)*2)
+ for i, pair := range actionEntry.Substitutions {
value := pair.Value
if val, ok := templateActionOverriddenTokens[pair.Key]; ok {
value = val
}
- replacerString = append(replacerString, pair.Key, value)
+ replacerString[i*2] = pair.Key
+ replacerString[i*2+1] = value
}
replacer := strings.NewReplacer(replacerString...)
return replacer.Replace(actionEntry.TemplateContent)
}
-func escapeCommandlineArgument(str string) string {
- // \->\\, $->\$, `->\`, "->\", \n->\\n, '->'"'"'
- replacer := strings.NewReplacer(
- `\`, `\\`,
- `$`, `\$`,
- "`", "\\`",
- `"`, `\"`,
- "\n", "\\n",
- `'`, `'"'"'`,
- )
- return replacer.Replace(str)
-}
-
-func (a action) isSymlinkAction() bool {
- return a.Mnemonic == "Symlink" || a.Mnemonic == "SolibSymlink" || a.Mnemonic == "ExecutableSymlink"
-}
-
-func (a action) isTemplateExpandAction() bool {
- return a.Mnemonic == "TemplateExpand"
-}
-
-func (a action) isFileWriteAction() bool {
- return a.Mnemonic == "FileWrite" || a.Mnemonic == "SourceSymlinkManifest"
-}
+// \->\\, $->\$, `->\`, "->\", \n->\\n, '->'"'"'
+var commandLineArgumentReplacer = strings.NewReplacer(
+ `\`, `\\`,
+ `$`, `\$`,
+ "`", "\\`",
+ `"`, `\"`,
+ "\n", "\\n",
+ `'`, `'"'"'`,
+)
-func (a action) isSymlinkTreeAction() bool {
- return a.Mnemonic == "SymlinkTree"
+func escapeCommandlineArgument(str string) string {
+ return commandLineArgumentReplacer.Replace(str)
}
-func shouldSkipAction(a action) bool {
+func (a *aqueryArtifactHandler) actionToBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
+ switch actionEntry.Mnemonic {
// Middleman actions are not handled like other actions; they are handled separately as a
// preparatory step so that their inputs may be relayed to actions depending on middleman
// artifacts.
- if a.Mnemonic == "Middleman" {
- return true
- }
+ case middlemanMnemonic:
+ return nil, nil
// PythonZipper is bogus action returned by aquery, ignore it (b/236198693)
- if a.Mnemonic == "PythonZipper" {
- return true
- }
+ case "PythonZipper":
+ return nil, nil
// Skip "Fail" actions, which are placeholder actions designed to always fail.
- if a.Mnemonic == "Fail" {
- return true
+ case "Fail":
+ return nil, nil
+ case "BaselineCoverage":
+ return nil, nil
+ case "Symlink", "SolibSymlink", "ExecutableSymlink":
+ return a.symlinkActionBuildStatement(actionEntry)
+ case "TemplateExpand":
+ if len(actionEntry.Arguments) < 1 {
+ return a.templateExpandActionBuildStatement(actionEntry)
+ }
+ case "FileWrite", "SourceSymlinkManifest":
+ return a.fileWriteActionBuildStatement(actionEntry)
+ case "SymlinkTree":
+ return a.symlinkTreeActionBuildStatement(actionEntry)
}
- if a.Mnemonic == "BaselineCoverage" {
- return true
+
+ if len(actionEntry.Arguments) < 1 {
+ return nil, fmt.Errorf("received action with no command: [%s]", actionEntry.Mnemonic)
}
- return false
+ return a.normalActionBuildStatement(actionEntry)
+
}
-func expandPathFragment(id pathFragmentId, pathFragmentsMap map[pathFragmentId]pathFragment) (string, error) {
+func expandPathFragment(id pathFragmentId, pathFragmentsMap map[pathFragmentId]*analysis_v2_proto.PathFragment) (string, error) {
var labels []string
currId := id
// Only positive IDs are valid for path fragments. An ID of zero indicates a terminal node.
@@ -711,10 +676,11 @@ func expandPathFragment(id pathFragmentId, pathFragmentsMap map[pathFragmentId]p
return "", fmt.Errorf("undefined path fragment id %d", currId)
}
labels = append([]string{currFragment.Label}, labels...)
- if currId == currFragment.ParentId {
+ parentId := pathFragmentId(currFragment.ParentId)
+ if currId == parentId {
return "", fmt.Errorf("fragment cannot refer to itself as parent %#v", currFragment)
}
- currId = currFragment.ParentId
+ currId = parentId
}
return filepath.Join(labels...), nil
}
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 4d1503ea1..19a584f23 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -21,8 +21,10 @@ import (
"sort"
"testing"
- "google.golang.org/protobuf/proto"
analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
+
+ "github.com/google/blueprint/metrics"
+ "google.golang.org/protobuf/proto"
)
func TestAqueryMultiArchGenrule(t *testing.T) {
@@ -136,18 +138,18 @@ func TestAqueryMultiArchGenrule(t *testing.T) {
t.Error(err)
return
}
- actualbuildStatements, actualDepsets, _ := AqueryBuildStatements(data)
- var expectedBuildStatements []BuildStatement
+ actualbuildStatements, actualDepsets, _ := AqueryBuildStatements(data, &metrics.EventHandler{})
+ var expectedBuildStatements []*BuildStatement
for _, arch := range []string{"arm", "arm64", "x86", "x86_64"} {
expectedBuildStatements = append(expectedBuildStatements,
- BuildStatement{
+ &BuildStatement{
Command: fmt.Sprintf(
"/bin/bash -c 'source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py %s ../sourceroot/bionic/libc/SYSCALLS.TXT > bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-%s.S'",
arch, arch),
OutputPaths: []string{
fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-%s.S", arch),
},
- Env: []KeyValuePair{
+ Env: []*analysis_v2_proto.KeyValuePair{
{Key: "PATH", Value: "/bin:/usr/bin:/usr/local/bin"},
},
Mnemonic: "Genrule",
@@ -195,7 +197,7 @@ func TestInvalidOutputId(t *testing.T) {
t.Error(err)
return
}
- _, _, err = AqueryBuildStatements(data)
+ _, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
assertError(t, err, "undefined outputId 3")
}
@@ -226,7 +228,7 @@ func TestInvalidInputDepsetIdFromAction(t *testing.T) {
t.Error(err)
return
}
- _, _, err = AqueryBuildStatements(data)
+ _, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
assertError(t, err, "undefined (not even empty) input depsetId 2")
}
@@ -257,7 +259,7 @@ func TestInvalidInputDepsetIdFromDepset(t *testing.T) {
t.Error(err)
return
}
- _, _, err = AqueryBuildStatements(data)
+ _, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
assertError(t, err, "undefined input depsetId 42 (referenced by depsetId 1)")
}
@@ -288,7 +290,7 @@ func TestInvalidInputArtifactId(t *testing.T) {
t.Error(err)
return
}
- _, _, err = AqueryBuildStatements(data)
+ _, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
assertError(t, err, "undefined input artifactId 3")
}
@@ -319,7 +321,7 @@ func TestInvalidPathFragmentId(t *testing.T) {
t.Error(err)
return
}
- _, _, err = AqueryBuildStatements(data)
+ _, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
assertError(t, err, "undefined path fragment id 3")
}
@@ -352,7 +354,7 @@ func TestDepfiles(t *testing.T) {
t.Error(err)
return
}
- actual, _, err := AqueryBuildStatements(data)
+ actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
}
@@ -402,7 +404,7 @@ func TestMultipleDepfiles(t *testing.T) {
t.Error(err)
return
}
- _, _, err = AqueryBuildStatements(data)
+ _, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
assertError(t, err, `found multiple potential depfiles "two.d", "other.d"`)
}
@@ -483,13 +485,14 @@ func TestTransitiveInputDepsets(t *testing.T) {
t.Error(err)
return
}
- actualbuildStatements, actualDepsets, _ := AqueryBuildStatements(data)
+ actualbuildStatements, actualDepsets, _ := AqueryBuildStatements(data, &metrics.EventHandler{})
- expectedBuildStatements := []BuildStatement{
- {
- Command: "/bin/bash -c 'touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out'",
- OutputPaths: []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"},
- Mnemonic: "Action",
+ expectedBuildStatements := []*BuildStatement{
+ &BuildStatement{
+ Command: "/bin/bash -c 'touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out'",
+ OutputPaths: []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"},
+ Mnemonic: "Action",
+ SymlinkPaths: []string{},
},
}
assertBuildStatements(t, expectedBuildStatements, actualbuildStatements)
@@ -538,16 +541,17 @@ func TestSymlinkTree(t *testing.T) {
t.Error(err)
return
}
- actual, _, err := AqueryBuildStatements(data)
+ actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
}
- assertBuildStatements(t, []BuildStatement{
- {
- Command: "",
- OutputPaths: []string{"foo.runfiles/MANIFEST"},
- Mnemonic: "SymlinkTree",
- InputPaths: []string{"foo.manifest"},
+ assertBuildStatements(t, []*BuildStatement{
+ &BuildStatement{
+ Command: "",
+ OutputPaths: []string{"foo.runfiles/MANIFEST"},
+ Mnemonic: "SymlinkTree",
+ InputPaths: []string{"foo.manifest"},
+ SymlinkPaths: []string{},
},
}, actual)
}
@@ -594,7 +598,7 @@ func TestBazelOutRemovalFromInputDepsets(t *testing.T) {
t.Error(err)
return
}
- actualBuildStatements, actualDepsets, _ := AqueryBuildStatements(data)
+ actualBuildStatements, actualDepsets, _ := AqueryBuildStatements(data, &metrics.EventHandler{})
if len(actualDepsets) != 1 {
t.Errorf("expected 1 depset but found %#v", actualDepsets)
return
@@ -611,10 +615,11 @@ func TestBazelOutRemovalFromInputDepsets(t *testing.T) {
t.Errorf("dependency ../dep2 expected but not found")
}
- expectedBuildStatement := BuildStatement{
- Command: "bogus command",
- OutputPaths: []string{"output"},
- Mnemonic: "x",
+ expectedBuildStatement := &BuildStatement{
+ Command: "bogus command",
+ OutputPaths: []string{"output"},
+ Mnemonic: "x",
+ SymlinkPaths: []string{},
}
buildStatementFound := false
for _, actualBuildStatement := range actualBuildStatements {
@@ -681,13 +686,13 @@ func TestBazelOutRemovalFromTransitiveInputDepsets(t *testing.T) {
t.Error(err)
return
}
- actualBuildStatements, actualDepsets, _ := AqueryBuildStatements(data)
+ actualBuildStatements, actualDepsets, _ := AqueryBuildStatements(data, &metrics.EventHandler{})
if len(actualDepsets) != 0 {
t.Errorf("expected 0 depsets but found %#v", actualDepsets)
return
}
- expectedBuildStatement := BuildStatement{
+ expectedBuildStatement := &BuildStatement{
Command: "bogus command",
OutputPaths: []string{"output"},
Mnemonic: "x",
@@ -748,12 +753,12 @@ func TestMiddlemenAction(t *testing.T) {
t.Error(err)
return
}
- actualBuildStatements, actualDepsets, err := AqueryBuildStatements(data)
+ actualBuildStatements, actualDepsets, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
}
- if expected := 1; len(actualBuildStatements) != expected {
- t.Fatalf("Expected %d build statements, got %d", expected, len(actualBuildStatements))
+ if expected := 2; len(actualBuildStatements) != expected {
+ t.Fatalf("Expected %d build statements, got %d %#v", expected, len(actualBuildStatements), actualBuildStatements)
}
expectedDepsetFiles := [][]string{
@@ -778,6 +783,11 @@ func TestMiddlemenAction(t *testing.T) {
if !reflect.DeepEqual(actualFlattenedInputs, expectedFlattenedInputs) {
t.Errorf("Expected flattened inputs %v, but got %v", expectedFlattenedInputs, actualFlattenedInputs)
}
+
+ bs = actualBuildStatements[1]
+ if bs != nil {
+ t.Errorf("Expected nil action for skipped")
+ }
}
// Returns the contents of given depsets in concatenated post order.
@@ -845,14 +855,14 @@ func TestSimpleSymlink(t *testing.T) {
t.Error(err)
return
}
- actual, _, err := AqueryBuildStatements(data)
+ actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
}
- expectedBuildStatements := []BuildStatement{
- {
+ expectedBuildStatements := []*BuildStatement{
+ &BuildStatement{
Command: "mkdir -p one/symlink_subdir && " +
"rm -f one/symlink_subdir/symlink && " +
"ln -sf $PWD/one/file_subdir/file one/symlink_subdir/symlink",
@@ -894,13 +904,13 @@ func TestSymlinkQuotesPaths(t *testing.T) {
t.Error(err)
return
}
- actual, _, err := AqueryBuildStatements(data)
+ actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
}
- expectedBuildStatements := []BuildStatement{
- {
+ expectedBuildStatements := []*BuildStatement{
+ &BuildStatement{
Command: "mkdir -p 'one/symlink subdir' && " +
"rm -f 'one/symlink subdir/symlink' && " +
"ln -sf $PWD/'one/file subdir/file' 'one/symlink subdir/symlink'",
@@ -940,7 +950,7 @@ func TestSymlinkMultipleInputs(t *testing.T) {
t.Error(err)
return
}
- _, _, err = AqueryBuildStatements(data)
+ _, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file" "other_file"], output ["symlink"]`)
}
@@ -971,7 +981,7 @@ func TestSymlinkMultipleOutputs(t *testing.T) {
t.Error(err)
return
}
- _, _, err = AqueryBuildStatements(data)
+ _, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
assertError(t, err, "undefined outputId 2")
}
@@ -1004,17 +1014,18 @@ func TestTemplateExpandActionSubstitutions(t *testing.T) {
t.Error(err)
return
}
- actual, _, err := AqueryBuildStatements(data)
+ actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
}
- expectedBuildStatements := []BuildStatement{
- {
+ expectedBuildStatements := []*BuildStatement{
+ &BuildStatement{
Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > template_file && " +
"chmod a+x template_file'",
- OutputPaths: []string{"template_file"},
- Mnemonic: "TemplateExpand",
+ OutputPaths: []string{"template_file"},
+ Mnemonic: "TemplateExpand",
+ SymlinkPaths: []string{},
},
}
assertBuildStatements(t, expectedBuildStatements, actual)
@@ -1046,7 +1057,7 @@ func TestTemplateExpandActionNoOutput(t *testing.T) {
t.Error(err)
return
}
- _, _, err = AqueryBuildStatements(data)
+ _, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
assertError(t, err, `Expect 1 output to template expand action, got: output []`)
}
@@ -1074,15 +1085,16 @@ func TestFileWrite(t *testing.T) {
t.Error(err)
return
}
- actual, _, err := AqueryBuildStatements(data)
+ actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
}
- assertBuildStatements(t, []BuildStatement{
- {
+ assertBuildStatements(t, []*BuildStatement{
+ &BuildStatement{
OutputPaths: []string{"foo.manifest"},
Mnemonic: "FileWrite",
FileContents: "file data\n",
+ SymlinkPaths: []string{},
},
}, actual)
}
@@ -1111,14 +1123,15 @@ func TestSourceSymlinkManifest(t *testing.T) {
t.Error(err)
return
}
- actual, _, err := AqueryBuildStatements(data)
+ actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
}
- assertBuildStatements(t, []BuildStatement{
- {
- OutputPaths: []string{"foo.manifest"},
- Mnemonic: "SourceSymlinkManifest",
+ assertBuildStatements(t, []*BuildStatement{
+ &BuildStatement{
+ OutputPaths: []string{"foo.manifest"},
+ Mnemonic: "SourceSymlinkManifest",
+ SymlinkPaths: []string{},
},
}, actual)
}
@@ -1134,7 +1147,7 @@ func assertError(t *testing.T, err error, expected string) {
// Asserts that the given actual build statements match the given expected build statements.
// Build statement equivalence is determined using buildStatementEquals.
-func assertBuildStatements(t *testing.T, expected []BuildStatement, actual []BuildStatement) {
+func assertBuildStatements(t *testing.T, expected []*BuildStatement, actual []*BuildStatement) {
t.Helper()
if len(expected) != len(actual) {
t.Errorf("expected %d build statements, but got %d,\n expected: %#v,\n actual: %#v",
@@ -1142,8 +1155,13 @@ func assertBuildStatements(t *testing.T, expected []BuildStatement, actual []Bui
return
}
type compareFn = func(i int, j int) bool
- byCommand := func(slice []BuildStatement) compareFn {
+ byCommand := func(slice []*BuildStatement) compareFn {
return func(i int, j int) bool {
+ if slice[i] == nil {
+ return false
+ } else if slice[j] == nil {
+ return false
+ }
return slice[i].Command < slice[j].Command
}
}
@@ -1159,7 +1177,10 @@ func assertBuildStatements(t *testing.T, expected []BuildStatement, actual []Bui
}
}
-func buildStatementEquals(first BuildStatement, second BuildStatement) string {
+func buildStatementEquals(first *BuildStatement, second *BuildStatement) string {
+ if (first == nil) != (second == nil) {
+ return "Nil"
+ }
if first.Mnemonic != second.Mnemonic {
return "Mnemonic"
}
diff --git a/bazel/bazel_proxy.go b/bazel/bazel_proxy.go
new file mode 100644
index 000000000..d7f5e6464
--- /dev/null
+++ b/bazel/bazel_proxy.go
@@ -0,0 +1,219 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bazel
+
+import (
+ "bytes"
+ "encoding/gob"
+ "fmt"
+ "net"
+ os_lib "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "time"
+)
+
+// Logs fatal events of ProxyServer.
+type ServerLogger interface {
+ Fatal(v ...interface{})
+ Fatalf(format string, v ...interface{})
+}
+
+// CmdRequest is a request to the Bazel Proxy server.
+type CmdRequest struct {
+ // Args to the Bazel command.
+ Argv []string
+ // Environment variables to pass to the Bazel invocation. Strings should be of
+ // the form "KEY=VALUE".
+ Env []string
+}
+
+// CmdResponse is a response from the Bazel Proxy server.
+type CmdResponse struct {
+ Stdout string
+ Stderr string
+ ErrorString string
+}
+
+// ProxyClient is a client which can issue Bazel commands to the Bazel
+// proxy server. Requests are issued (and responses received) via a unix socket.
+// See ProxyServer for more details.
+type ProxyClient struct {
+ outDir string
+}
+
+// ProxyServer is a server which runs as a background goroutine. Each
+// request to the server describes a Bazel command which the server should run.
+// The server then issues the Bazel command, and returns a response describing
+// the stdout/stderr of the command.
+// Client-server communication is done via a unix socket under the output
+// directory.
+// The server is intended to circumvent sandboxing for subprocesses of the
+// build. The build orchestrator (soong_ui) can launch a server to exist outside
+// of sandboxing, and sandboxed processes (such as soong_build) can issue
+// bazel commands through this socket tunnel. This allows a sandboxed process
+// to issue bazel requests to a bazel that resides outside of sandbox. This
+// is particularly useful to maintain a persistent Bazel server which lives
+// past the duration of a single build.
+// The ProxyServer will only live as long as soong_ui does; the
+// underlying Bazel server will live past the duration of the build.
+type ProxyServer struct {
+ logger ServerLogger
+ outDir string
+ workspaceDir string
+ // The server goroutine will listen on this channel and stop handling requests
+ // once it is written to.
+ done chan struct{}
+}
+
+// NewProxyClient is a constructor for a ProxyClient.
+func NewProxyClient(outDir string) *ProxyClient {
+ return &ProxyClient{
+ outDir: outDir,
+ }
+}
+
+func unixSocketPath(outDir string) string {
+ return filepath.Join(outDir, "bazelsocket.sock")
+}
+
+// IssueCommand issues a request to the Bazel Proxy Server to issue a Bazel
+// request. Returns a response describing the output from the Bazel process
+// (if the Bazel process had an error, then the response will include an error).
+// Returns an error if there was an issue with the connection to the Bazel Proxy
+// server.
+func (b *ProxyClient) IssueCommand(req CmdRequest) (CmdResponse, error) {
+ var resp CmdResponse
+ var err error
+ // Check for connections every 1 second. This is chosen to be a relatively
+ // short timeout, because the proxy server should accept requests quite
+ // quickly.
+ d := net.Dialer{Timeout: 1 * time.Second}
+ var conn net.Conn
+ conn, err = d.Dial("unix", unixSocketPath(b.outDir))
+ if err != nil {
+ return resp, err
+ }
+ defer conn.Close()
+
+ enc := gob.NewEncoder(conn)
+ if err = enc.Encode(req); err != nil {
+ return resp, err
+ }
+ dec := gob.NewDecoder(conn)
+ err = dec.Decode(&resp)
+ return resp, err
+}
+
+// NewProxyServer is a constructor for a ProxyServer.
+func NewProxyServer(logger ServerLogger, outDir string, workspaceDir string) *ProxyServer {
+ return &ProxyServer{
+ logger: logger,
+ outDir: outDir,
+ workspaceDir: workspaceDir,
+ done: make(chan struct{}),
+ }
+}
+
+func (b *ProxyServer) handleRequest(conn net.Conn) error {
+ defer conn.Close()
+
+ dec := gob.NewDecoder(conn)
+ var req CmdRequest
+ if err := dec.Decode(&req); err != nil {
+ return fmt.Errorf("Error decoding request: %s", err)
+ }
+
+ bazelCmd := exec.Command("./build/bazel/bin/bazel", req.Argv...)
+ bazelCmd.Dir = b.workspaceDir
+ bazelCmd.Env = req.Env
+
+ stderr := &bytes.Buffer{}
+ bazelCmd.Stderr = stderr
+ var stdout string
+ var bazelErrString string
+
+ if output, err := bazelCmd.Output(); err != nil {
+ bazelErrString = fmt.Sprintf("bazel command failed: %s\n---command---\n%s\n---env---\n%s\n---stderr---\n%s---",
+ err, bazelCmd, strings.Join(bazelCmd.Env, "\n"), stderr)
+ } else {
+ stdout = string(output)
+ }
+
+ resp := CmdResponse{stdout, string(stderr.Bytes()), bazelErrString}
+ enc := gob.NewEncoder(conn)
+ if err := enc.Encode(&resp); err != nil {
+ return fmt.Errorf("Error encoding response: %s", err)
+ }
+ return nil
+}
+
+func (b *ProxyServer) listenUntilClosed(listener net.Listener) error {
+ for {
+ // Check for connections every 1 second. This is a blocking operation, so
+ // if the server is closed, the goroutine will not fully close until this
+ // deadline is reached. Thus, this deadline is short (but not too short
+ // so that the routine churns).
+ listener.(*net.UnixListener).SetDeadline(time.Now().Add(time.Second))
+ conn, err := listener.Accept()
+
+ select {
+ case <-b.done:
+ return nil
+ default:
+ }
+
+ if err != nil {
+ if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() {
+ // Timeout is normal and expected while waiting for client to establish
+ // a connection.
+ continue
+ } else {
+ b.logger.Fatalf("Listener error: %s", err)
+ }
+ }
+
+ err = b.handleRequest(conn)
+ if err != nil {
+ b.logger.Fatal(err)
+ }
+ }
+}
+
+// Start initializes the server unix socket and (in a separate goroutine)
+// handles requests on the socket until the server is closed. Returns an error
+// if a failure occurs during initialization. Will log any post-initialization
+// errors to the server's logger.
+func (b *ProxyServer) Start() error {
+ unixSocketAddr := unixSocketPath(b.outDir)
+ if err := os_lib.RemoveAll(unixSocketAddr); err != nil {
+ return fmt.Errorf("couldn't remove socket '%s': %s", unixSocketAddr, err)
+ }
+ listener, err := net.Listen("unix", unixSocketAddr)
+
+ if err != nil {
+ return fmt.Errorf("error listening on socket '%s': %s", unixSocketAddr, err)
+ }
+
+ go b.listenUntilClosed(listener)
+ return nil
+}
+
+// Close shuts down the server. This will stop the server from listening for
+// additional requests.
+func (b *ProxyServer) Close() {
+ b.done <- struct{}{}
+}
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index 665419100..0c8247a34 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -180,7 +180,7 @@ else:
tidy_files = []
clang_tidy_info = p.get("//build/bazel/rules/cc:clang_tidy.bzl%ClangTidyInfo")
if clang_tidy_info:
- tidy_files = [v.path for v in clang_tidy_info.tidy_files.to_list()]
+ tidy_files = [v.path for v in clang_tidy_info.transitive_tidy_files.to_list()]
abi_diff_files = []
abi_diff_info = p.get("//build/bazel/rules/abi:abi_dump.bzl%AbiDiffInfo")
@@ -207,7 +207,7 @@ return json_encode({
"Headers": headers,
"RootStaticArchives": rootStaticArchives,
"RootDynamicLibraries": rootSharedLibraries,
- "TidyFiles": tidy_files,
+ "TidyFiles": [t for t in tidy_files],
"TocFile": toc_file,
"UnstrippedOutput": unstripped,
"AbiDiffFiles": abi_diff_files,
@@ -261,6 +261,11 @@ mk_info = providers(target).get("//build/bazel/rules/apex:apex_info.bzl%ApexMkIn
if not mk_info:
fail("%s did not provide ApexMkInfo" % id_string)
+tidy_files = []
+clang_tidy_info = providers(target).get("//build/bazel/rules/cc:clang_tidy.bzl%ClangTidyInfo")
+if clang_tidy_info:
+ tidy_files = [v.path for v in clang_tidy_info.transitive_tidy_files.to_list()]
+
return json_encode({
"signed_output": info.signed_output.path,
"signed_compressed_output": signed_compressed_output,
@@ -276,6 +281,7 @@ return json_encode({
"bundle_file": info.base_with_config_zip.path,
"installed_files": info.installed_files.path,
"make_modules_to_install": mk_info.make_modules_to_install,
+ "tidy_files": [t for t in tidy_files],
})`
}
@@ -294,6 +300,7 @@ type ApexInfo struct {
BackingLibs string `json:"backing_libs"`
BundleFile string `json:"bundle_file"`
InstalledFiles string `json:"installed_files"`
+ TidyFiles []string `json:"tidy_files"`
// From the ApexMkInfo provider
MakeModulesToInstall []string `json:"make_modules_to_install"`
@@ -338,12 +345,18 @@ if androidmk_tag in p:
local_whole_static_libs = androidmk_info.local_whole_static_libs
local_shared_libs = androidmk_info.local_shared_libs
+tidy_files = []
+clang_tidy_info = p.get("//build/bazel/rules/cc:clang_tidy.bzl%ClangTidyInfo")
+if clang_tidy_info:
+ tidy_files = [v.path for v in clang_tidy_info.transitive_tidy_files.to_list()]
+
return json_encode({
"OutputFile": output_path,
"UnstrippedOutput": unstripped,
"LocalStaticLibs": [l for l in local_static_libs],
"LocalWholeStaticLibs": [l for l in local_whole_static_libs],
"LocalSharedLibs": [l for l in local_shared_libs],
+ "TidyFiles": [t for t in tidy_files],
})
`
}
@@ -361,6 +374,7 @@ type CcUnstrippedInfo struct {
CcAndroidMkInfo
OutputFile string
UnstrippedOutput string
+ TidyFiles []string
}
// splitOrEmpty is a modification of strings.Split() that returns an empty list
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index 86b9b27e2..d1dfb9d36 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -17,21 +17,57 @@ package bp2build
import (
"fmt"
"os"
+ "path/filepath"
"strings"
"android/soong/android"
"android/soong/bazel"
+ "android/soong/shared"
)
+func deleteFilesExcept(ctx *CodegenContext, rootOutputPath android.OutputPath, except []BazelFile) {
+ // Delete files that should no longer be present.
+ bp2buildDirAbs := shared.JoinPath(ctx.topDir, rootOutputPath.String())
+
+ filesToDelete := make(map[string]struct{})
+ err := filepath.Walk(bp2buildDirAbs,
+ func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if !info.IsDir() {
+ relPath, err := filepath.Rel(bp2buildDirAbs, path)
+ if err != nil {
+ return err
+ }
+ filesToDelete[relPath] = struct{}{}
+ }
+ return nil
+ })
+ if err != nil {
+ fmt.Printf("ERROR reading %s: %s", bp2buildDirAbs, err)
+ os.Exit(1)
+ }
+
+ for _, bazelFile := range except {
+ filePath := filepath.Join(bazelFile.Dir, bazelFile.Basename)
+ delete(filesToDelete, filePath)
+ }
+ for f, _ := range filesToDelete {
+ absPath := shared.JoinPath(bp2buildDirAbs, f)
+ if err := os.RemoveAll(absPath); err != nil {
+ fmt.Printf("ERROR deleting %s: %s", absPath, err)
+ os.Exit(1)
+ }
+ }
+}
+
// Codegen is the backend of bp2build. The code generator is responsible for
// writing .bzl files that are equivalent to Android.bp files that are capable
// of being built with Bazel.
func Codegen(ctx *CodegenContext) *CodegenMetrics {
// This directory stores BUILD files that could be eventually checked-in.
bp2buildDir := android.PathForOutput(ctx, "bp2build")
- if err := android.RemoveAllOutputDir(bp2buildDir); err != nil {
- fmt.Printf("ERROR: Encountered error while cleaning %s: %s", bp2buildDir, err.Error())
- }
res, errs := GenerateBazelTargets(ctx, true)
if len(errs) > 0 {
@@ -44,10 +80,19 @@ func Codegen(ctx *CodegenContext) *CodegenMetrics {
}
bp2buildFiles := CreateBazelFiles(ctx.Config(), nil, res.buildFileToTargets, ctx.mode)
writeFiles(ctx, bp2buildDir, bp2buildFiles)
+ // Delete files under the bp2build root which weren't just written. An
+ // alternative would have been to delete the whole directory and write these
+ // files. However, this would regenerate files which were otherwise unchanged
+ // since the last bp2build run, which would have negative incremental
+ // performance implications.
+ deleteFilesExcept(ctx, bp2buildDir, bp2buildFiles)
- soongInjectionDir := android.PathForOutput(ctx, bazel.SoongInjectionDirName)
- writeFiles(ctx, soongInjectionDir, CreateSoongInjectionDirFiles(ctx, res.metrics))
-
+ injectionFiles, err := CreateSoongInjectionDirFiles(ctx, res.metrics)
+ if err != nil {
+ fmt.Printf("%s\n", err.Error())
+ os.Exit(1)
+ }
+ writeFiles(ctx, android.PathForOutput(ctx, bazel.SoongInjectionDirName), injectionFiles)
return &res.metrics
}
@@ -55,17 +100,20 @@ func Codegen(ctx *CodegenContext) *CodegenMetrics {
// This includes
// 1. config value(s) that are hardcoded in Soong
// 2. product_config variables
-func CreateSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) []BazelFile {
+func CreateSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, error) {
var ret []BazelFile
productConfigFiles, err := CreateProductConfigFiles(ctx)
if err != nil {
- fmt.Printf("ERROR: %s", err.Error())
- os.Exit(1)
+ return nil, err
}
ret = append(ret, productConfigFiles...)
- ret = append(ret, soongInjectionFiles(ctx.Config(), metrics)...)
- return ret
+ injectionFiles, err := soongInjectionFiles(ctx.Config(), metrics)
+ if err != nil {
+ return nil, err
+ }
+ ret = append(ret, injectionFiles...)
+ return ret, nil
}
// Get the output directory and create it if it doesn't exist.
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 6c6631abe..ced779c33 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -227,7 +227,7 @@ func NewCodegenContext(config android.Config, context *android.Context, mode Cod
// the generated attributes are sorted to ensure determinism.
func propsToAttributes(props map[string]string) string {
var attributes string
- for _, propName := range android.SortedStringKeys(props) {
+ for _, propName := range android.SortedKeys(props) {
attributes += fmt.Sprintf(" %s = %s,\n", propName, props[propName])
}
return attributes
diff --git a/bp2build/bzl_conversion.go b/bp2build/bzl_conversion.go
index 992cc1c8c..e774fdf36 100644
--- a/bp2build/bzl_conversion.go
+++ b/bp2build/bzl_conversion.go
@@ -83,7 +83,7 @@ func CreateRuleShims(moduleTypeFactories map[string]android.ModuleFactory) map[s
func generateSoongModuleBzl(bzlLoads map[string]RuleShim) string {
var loadStmts string
var moduleRuleMap string
- for _, bzlFileName := range android.SortedStringKeys(bzlLoads) {
+ for _, bzlFileName := range android.SortedKeys(bzlLoads) {
loadStmt := "load(\"//build/bazel/queryview_rules:"
loadStmt += bzlFileName
loadStmt += ".bzl\""
@@ -104,7 +104,7 @@ func generateRules(moduleTypeFactories map[string]android.ModuleFactory) map[str
rules := make(map[string][]rule)
// TODO: allow registration of a bzl rule when registring a factory
- for _, moduleType := range android.SortedStringKeys(moduleTypeFactories) {
+ for _, moduleType := range android.SortedKeys(moduleTypeFactories) {
factory := moduleTypeFactories[moduleType]
factoryName := runtime.FuncForPC(reflect.ValueOf(factory).Pointer()).Name()
pkg := strings.Split(factoryName, ".")[0]
@@ -221,7 +221,7 @@ func getPropertyDescriptions(props []interface{}) []property {
}
properties := make([]property, 0, len(propertiesByName))
- for _, key := range android.SortedStringKeys(propertiesByName) {
+ for _, key := range android.SortedKeys(propertiesByName) {
properties = append(properties, propertiesByName[key])
}
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index fe156dffd..a39ed7de6 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -365,7 +365,7 @@ func TestCcBinaryNocrtTests(t *testing.T) {
{
description: "nocrt: true",
soongProperty: `nocrt: true,`,
- bazelAttr: AttrNameToString{"link_crt": `False`},
+ bazelAttr: AttrNameToString{"features": `["-link_crt"]`},
},
{
description: "nocrt: false",
@@ -408,12 +408,12 @@ func TestCcBinaryNo_libcrtTests(t *testing.T) {
{
description: "no_libcrt: true",
soongProperty: `no_libcrt: true,`,
- bazelAttr: AttrNameToString{"use_libcrt": `False`},
+ bazelAttr: AttrNameToString{"features": `["-use_libcrt"]`},
},
{
description: "no_libcrt: false",
soongProperty: `no_libcrt: false,`,
- bazelAttr: AttrNameToString{"use_libcrt": `True`},
+ bazelAttr: AttrNameToString{},
},
{
description: "no_libcrt: not set",
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index c11a50d9d..af14f6438 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -1308,7 +1308,7 @@ cc_library {
func TestCCLibraryNoCrtTrue(t *testing.T) {
runCcLibraryTestCase(t, Bp2buildTestCase{
- Description: "cc_library - nocrt: true emits attribute",
+ Description: "cc_library - nocrt: true disables feature",
ModuleTypeUnderTest: "cc_library",
ModuleTypeUnderTestFactory: cc.LibraryFactory,
Filesystem: map[string]string{
@@ -1323,7 +1323,7 @@ cc_library {
}
`,
ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
- "link_crt": `False`,
+ "features": `["-link_crt"]`,
"srcs": `["impl.cpp"]`,
}),
},
@@ -1375,7 +1375,13 @@ cc_library {
include_build_directory: false,
}
`,
- ExpectedErr: fmt.Errorf("module \"foo-lib\": nocrt is not supported for arch variants"),
+ ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
+ "features": `select({
+ "//build/bazel/platforms/arch:arm": ["-link_crt"],
+ "//conditions:default": [],
+ })`,
+ "srcs": `["impl.cpp"]`,
+ }),
})
}
@@ -1395,8 +1401,8 @@ cc_library {
}
`,
ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
- "srcs": `["impl.cpp"]`,
- "use_libcrt": `False`,
+ "features": `["-use_libcrt"]`,
+ "srcs": `["impl.cpp"]`,
}),
})
}
@@ -1445,8 +1451,7 @@ cc_library {
}
`,
ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
- "srcs": `["impl.cpp"]`,
- "use_libcrt": `True`,
+ "srcs": `["impl.cpp"]`,
}),
})
}
@@ -1475,10 +1480,10 @@ cc_library {
`,
ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
"srcs": `["impl.cpp"]`,
- "use_libcrt": `select({
- "//build/bazel/platforms/arch:arm": False,
- "//build/bazel/platforms/arch:x86": False,
- "//conditions:default": None,
+ "features": `select({
+ "//build/bazel/platforms/arch:arm": ["-use_libcrt"],
+ "//build/bazel/platforms/arch:x86": ["-use_libcrt"],
+ "//conditions:default": [],
})`,
}),
})
@@ -1512,17 +1517,15 @@ cc_library {
}
`,
ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
- "srcs": `["impl.cpp"]`,
- "use_libcrt": `select({
- "//build/bazel/platforms/os_arch:android_arm": False,
- "//build/bazel/platforms/os_arch:android_x86": False,
- "//build/bazel/platforms/os_arch:darwin_arm64": False,
- "//build/bazel/platforms/os_arch:darwin_x86_64": False,
- "//build/bazel/platforms/os_arch:linux_glibc_x86": False,
- "//build/bazel/platforms/os_arch:linux_musl_x86": False,
- "//build/bazel/platforms/os_arch:windows_x86": False,
- "//conditions:default": None,
+ "features": `select({
+ "//build/bazel/platforms/arch:arm": ["-use_libcrt"],
+ "//build/bazel/platforms/arch:x86": ["-use_libcrt"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os:darwin": ["-use_libcrt"],
+ "//conditions:default": [],
})`,
+ "srcs": `["impl.cpp"]`,
}),
})
}
@@ -1557,16 +1560,10 @@ cc_library {
`,
ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
"srcs": `["impl.cpp"]`,
- "use_libcrt": `select({
- "//build/bazel/platforms/os_arch:android_arm": False,
- "//build/bazel/platforms/os_arch:android_x86_64": False,
- "//build/bazel/platforms/os_arch:darwin_arm64": True,
- "//build/bazel/platforms/os_arch:darwin_x86_64": False,
- "//build/bazel/platforms/os_arch:linux_bionic_x86_64": False,
- "//build/bazel/platforms/os_arch:linux_glibc_x86_64": False,
- "//build/bazel/platforms/os_arch:linux_musl_x86_64": False,
- "//build/bazel/platforms/os_arch:windows_x86_64": False,
- "//conditions:default": None,
+ "features": `select({
+ "//build/bazel/platforms/arch:arm": ["-use_libcrt"],
+ "//build/bazel/platforms/arch:x86_64": ["-use_libcrt"],
+ "//conditions:default": [],
})`,
}),
})
@@ -4087,3 +4084,56 @@ cc_library {
},
})
}
+
+func TestCcLibraryInApexWithStubSharedLibs(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library with in apex with stub shared_libs and export_shared_lib_headers",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "barlib",
+ stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] },
+ bazel_module: { bp2build_available: false },
+}
+cc_library {
+ name: "bazlib",
+ stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] },
+ bazel_module: { bp2build_available: false },
+}
+cc_library {
+ name: "foo",
+ shared_libs: ["barlib", "bazlib"],
+ export_shared_lib_headers: ["bazlib"],
+ apex_available: [
+ "apex_available:platform",
+ ],
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "implementation_dynamic_deps": `select({
+ "//build/bazel/rules/apex:android-in_apex": [":barlib_stub_libs_current"],
+ "//conditions:default": [":barlib"],
+ })`,
+ "dynamic_deps": `select({
+ "//build/bazel/rules/apex:android-in_apex": [":bazlib_stub_libs_current"],
+ "//conditions:default": [":bazlib"],
+ })`,
+ "local_includes": `["."]`,
+ "tags": `["apex_available=apex_available:platform"]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "implementation_dynamic_deps": `select({
+ "//build/bazel/rules/apex:android-in_apex": [":barlib_stub_libs_current"],
+ "//conditions:default": [":barlib"],
+ })`,
+ "dynamic_deps": `select({
+ "//build/bazel/rules/apex:android-in_apex": [":bazlib_stub_libs_current"],
+ "//conditions:default": [":bazlib"],
+ })`,
+ "local_includes": `["."]`,
+ "tags": `["apex_available=apex_available:platform"]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index 017df6f9c..620742115 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -15,7 +15,6 @@
package bp2build
import (
- "fmt"
"testing"
"android/soong/android"
@@ -405,7 +404,7 @@ cc_library_shared {
func TestCcLibrarySharedNoCrtTrue(t *testing.T) {
runCcLibrarySharedTestCase(t, Bp2buildTestCase{
- Description: "cc_library_shared - nocrt: true emits attribute",
+ Description: "cc_library_shared - nocrt: true disables feature",
Filesystem: map[string]string{
"impl.cpp": "",
},
@@ -419,7 +418,7 @@ cc_library_shared {
`,
ExpectedBazelTargets: []string{
MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
- "link_crt": `False`,
+ "features": `["-link_crt"]`,
"srcs": `["impl.cpp"]`,
}),
},
@@ -428,7 +427,7 @@ cc_library_shared {
func TestCcLibrarySharedNoCrtFalse(t *testing.T) {
runCcLibrarySharedTestCase(t, Bp2buildTestCase{
- Description: "cc_library_shared - nocrt: false doesn't emit attribute",
+ Description: "cc_library_shared - nocrt: false doesn't disable feature",
Filesystem: map[string]string{
"impl.cpp": "",
},
@@ -469,7 +468,15 @@ cc_library_shared {
include_build_directory: false,
}
`,
- ExpectedErr: fmt.Errorf("module \"foo_shared\": nocrt is not supported for arch variants"),
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
+ "features": `select({
+ "//build/bazel/platforms/arch:arm": ["-link_crt"],
+ "//conditions:default": [],
+ })`,
+ "srcs": `["impl.cpp"]`,
+ }),
+ },
})
}
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index 2a0a78e59..8e171031c 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -256,7 +256,7 @@ func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *stri
}
var selects string
- for _, selectKey := range android.SortedStringKeys(selectMap) {
+ for _, selectKey := range android.SortedKeys(selectMap) {
if selectKey == bazel.ConditionsDefaultSelectKey {
// Handle default condition later.
continue
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index c43fbd86e..6a39e256a 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -22,7 +22,7 @@ type BazelFile struct {
}
// PRIVATE: Use CreateSoongInjectionDirFiles instead
-func soongInjectionFiles(cfg android.Config, metrics CodegenMetrics) []BazelFile {
+func soongInjectionFiles(cfg android.Config, metrics CodegenMetrics) ([]BazelFile, error) {
var files []BazelFile
files = append(files, newFile("android", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package.
@@ -36,7 +36,11 @@ func soongInjectionFiles(cfg android.Config, metrics CodegenMetrics) []BazelFile
files = append(files, newFile("java_toolchain", "constants.bzl", java_config.BazelJavaToolchainVars(cfg)))
files = append(files, newFile("apex_toolchain", GeneratedBuildFileName, "")) // Creates a //apex_toolchain package.
- files = append(files, newFile("apex_toolchain", "constants.bzl", apex.BazelApexToolchainVars()))
+ apexToolchainVars, err := apex.BazelApexToolchainVars()
+ if err != nil {
+ return nil, err
+ }
+ files = append(files, newFile("apex_toolchain", "constants.bzl", apexToolchainVars))
files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.Serialize().ConvertedModules, "\n")))
@@ -52,17 +56,20 @@ func soongInjectionFiles(cfg android.Config, metrics CodegenMetrics) []BazelFile
apiLevelsContent, err := json.Marshal(android.GetApiLevelsMap(cfg))
if err != nil {
- panic(err)
+ return nil, err
}
files = append(files, newFile("api_levels", GeneratedBuildFileName, `exports_files(["api_levels.json"])`))
+ // TODO(b/269691302) value of apiLevelsContent is product variable dependent and should be avoided for soong injection
files = append(files, newFile("api_levels", "api_levels.json", string(apiLevelsContent)))
files = append(files, newFile("api_levels", "api_levels.bzl", android.StarlarkApiLevelConfigs(cfg)))
+ files = append(files, newFile("allowlists", GeneratedBuildFileName, ""))
+ files = append(files, newFile("allowlists", "env.bzl", android.EnvironmentVarsFile(cfg)))
// TODO(b/262781701): Create an alternate soong_build entrypoint for writing out these files only when requested
files = append(files, newFile("allowlists", "mixed_build_prod_allowlist.txt", strings.Join(android.GetBazelEnabledModules(android.BazelProdMode), "\n")+"\n"))
files = append(files, newFile("allowlists", "mixed_build_staging_allowlist.txt", strings.Join(android.GetBazelEnabledModules(android.BazelStagingMode), "\n")+"\n"))
- return files
+ return files, nil
}
func CreateBazelFiles(
@@ -98,7 +105,7 @@ func CreateBazelFiles(
func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
files := make([]BazelFile, 0, len(buildToTargets))
- for _, dir := range android.SortedStringKeys(buildToTargets) {
+ for _, dir := range android.SortedKeys(buildToTargets) {
targets := buildToTargets[dir]
targets.sort()
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index b9c06bc04..8c1d2ae5b 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -84,8 +84,10 @@ func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) {
func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) {
testConfig := android.TestConfig("", make(map[string]string), "", make(map[string][]byte))
- files := soongInjectionFiles(testConfig, CreateCodegenMetrics())
-
+ files, err := soongInjectionFiles(testConfig, CreateCodegenMetrics())
+ if err != nil {
+ t.Error(err)
+ }
expectedFilePaths := []bazelFilepath{
{
dir: "android",
@@ -153,6 +155,14 @@ func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) {
},
{
dir: "allowlists",
+ basename: GeneratedBuildFileName,
+ },
+ {
+ dir: "allowlists",
+ basename: "env.bzl",
+ },
+ {
+ dir: "allowlists",
basename: "mixed_build_prod_allowlist.txt",
},
{
diff --git a/bp2build/java_sdk_library_conversion_test.go b/bp2build/java_sdk_library_conversion_test.go
new file mode 100644
index 000000000..9ce7446c2
--- /dev/null
+++ b/bp2build/java_sdk_library_conversion_test.go
@@ -0,0 +1,148 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bp2build
+
+import (
+ "testing"
+
+ "android/soong/android"
+ "android/soong/java"
+)
+
+func runJavaSdkLibraryTestCaseWithRegistrationCtxFunc(t *testing.T, tc Bp2buildTestCase, registrationCtxFunc func(ctx android.RegistrationContext)) {
+ t.Helper()
+ (&tc).ModuleTypeUnderTest = "java_sdk_library"
+ (&tc).ModuleTypeUnderTestFactory = java.SdkLibraryFactory
+ RunBp2BuildTestCase(t, registrationCtxFunc, tc)
+}
+
+func runJavaSdkLibraryTestCase(t *testing.T, tc Bp2buildTestCase) {
+ t.Helper()
+ runJavaSdkLibraryTestCaseWithRegistrationCtxFunc(t, tc, func(ctx android.RegistrationContext) {})
+}
+
+func TestJavaSdkLibraryApiSurfaceGeneral(t *testing.T) {
+ runJavaSdkLibraryTestCase(t, Bp2buildTestCase{
+ Description: "limited java_sdk_library for api surfaces, general conversion",
+ Filesystem: map[string]string{
+ "build/soong/scripts/gen-java-current-api-files.sh": "",
+ "api/current.txt": "",
+ "api/system-current.txt": "",
+ "api/test-current.txt": "",
+ "api/module-lib-current.txt": "",
+ "api/system-server-current.txt": "",
+ "api/removed.txt": "",
+ "api/system-removed.txt": "",
+ "api/test-removed.txt": "",
+ "api/module-lib-removed.txt": "",
+ "api/system-server-removed.txt": "",
+ },
+ Blueprint: `java_sdk_library {
+ name: "java-sdk-lib",
+ srcs: ["a.java"],
+ public: {enabled: true},
+ system: {enabled: true},
+ test: {enabled: true},
+ module_lib: {enabled: true},
+ system_server: {enabled: true},
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("java_sdk_library", "java-sdk-lib", AttrNameToString{
+ "public": `"api/current.txt"`,
+ "system": `"api/system-current.txt"`,
+ "test": `"api/test-current.txt"`,
+ "module_lib": `"api/module-lib-current.txt"`,
+ "system_server": `"api/system-server-current.txt"`,
+ }),
+ },
+ })
+}
+
+func TestJavaSdkLibraryApiSurfacePublicDefault(t *testing.T) {
+ runJavaSdkLibraryTestCase(t, Bp2buildTestCase{
+ Description: "limited java_sdk_library for api surfaces, public prop uses default value",
+ Filesystem: map[string]string{
+ "build/soong/scripts/gen-java-current-api-files.sh": "",
+ "api/current.txt": "",
+ "api/system-current.txt": "",
+ "api/test-current.txt": "",
+ "api/module-lib-current.txt": "",
+ "api/system-server-current.txt": "",
+ "api/removed.txt": "",
+ "api/system-removed.txt": "",
+ "api/test-removed.txt": "",
+ "api/module-lib-removed.txt": "",
+ "api/system-server-removed.txt": "",
+ },
+ Blueprint: `java_sdk_library {
+ name: "java-sdk-lib",
+ srcs: ["a.java"],
+ system: {enabled: false},
+ test: {enabled: false},
+ module_lib: {enabled: false},
+ system_server: {enabled: false},
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("java_sdk_library", "java-sdk-lib", AttrNameToString{
+ "public": `"api/current.txt"`,
+ }),
+ },
+ })
+}
+
+func TestJavaSdkLibraryApiSurfacePublicNotEnabled(t *testing.T) {
+ runJavaSdkLibraryTestCase(t, Bp2buildTestCase{
+ Description: "limited java_sdk_library for api surfaces, public enable is false",
+ Filesystem: map[string]string{
+ "build/soong/scripts/gen-java-current-api-files.sh": "",
+ "api/current.txt": "",
+ "api/removed.txt": "",
+ },
+ Blueprint: `java_sdk_library {
+ name: "java-sdk-lib",
+ srcs: ["a.java"],
+ public: {enabled: false},
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("java_sdk_library", "java-sdk-lib", AttrNameToString{}),
+ },
+ })
+}
+
+func TestJavaSdkLibraryApiSurfaceNoScopeIsSet(t *testing.T) {
+ runJavaSdkLibraryTestCase(t, Bp2buildTestCase{
+ Description: "limited java_sdk_library for api surfaces, none of the api scopes is set",
+ Filesystem: map[string]string{
+ "build/soong/scripts/gen-java-current-api-files.sh": "",
+ "api/current.txt": "",
+ "api/system-current.txt": "",
+ "api/test-current.txt": "",
+ "api/removed.txt": "",
+ "api/system-removed.txt": "",
+ "api/test-removed.txt": "",
+ },
+ Blueprint: `java_sdk_library {
+ name: "java-sdk-lib",
+ srcs: ["a.java"],
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("java_sdk_library", "java-sdk-lib", AttrNameToString{
+ "public": `"api/current.txt"`,
+ "system": `"api/system-current.txt"`,
+ "test": `"api/test-current.txt"`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/metrics.go b/bp2build/metrics.go
index 7e29fac58..a02065081 100644
--- a/bp2build/metrics.go
+++ b/bp2build/metrics.go
@@ -51,7 +51,7 @@ func (metrics *CodegenMetrics) Serialize() *bp2build_metrics_proto.Bp2BuildMetri
// Print the codegen metrics to stdout.
func (metrics *CodegenMetrics) Print() {
generatedTargetCount := uint64(0)
- for _, ruleClass := range android.SortedStringKeys(metrics.serialized.RuleClassCount) {
+ for _, ruleClass := range android.SortedKeys(metrics.serialized.RuleClassCount) {
count := metrics.serialized.RuleClassCount[ruleClass]
fmt.Printf("[bp2build] %s: %d targets\n", ruleClass, count)
generatedTargetCount += count
diff --git a/bp2build/symlink_forest.go b/bp2build/symlink_forest.go
index 37188f196..aac5e7d2c 100644
--- a/bp2build/symlink_forest.go
+++ b/bp2build/symlink_forest.go
@@ -15,9 +15,7 @@
package bp2build
import (
- "errors"
"fmt"
- "io/fs"
"io/ioutil"
"os"
"path/filepath"
@@ -27,6 +25,7 @@ import (
"sync/atomic"
"android/soong/shared"
+ "github.com/google/blueprint/pathtools"
)
// A tree structure that describes what to do at each directory in the created
@@ -53,59 +52,6 @@ type symlinkForestContext struct {
symlinkCount atomic.Uint64
}
-// A simple thread pool to limit concurrency on system calls.
-// Necessary because Go spawns a new OS-level thread for each blocking system
-// call. This means that if syscalls are too slow and there are too many of
-// them, the hard limit on OS-level threads can be exhausted.
-type syscallPool struct {
- shutdownCh []chan<- struct{}
- workCh chan syscall
-}
-
-type syscall struct {
- work func()
- done chan<- struct{}
-}
-
-func createSyscallPool(count int) *syscallPool {
- result := &syscallPool{
- shutdownCh: make([]chan<- struct{}, count),
- workCh: make(chan syscall),
- }
-
- for i := 0; i < count; i++ {
- shutdownCh := make(chan struct{})
- result.shutdownCh[i] = shutdownCh
- go result.worker(shutdownCh)
- }
-
- return result
-}
-
-func (p *syscallPool) do(work func()) {
- doneCh := make(chan struct{})
- p.workCh <- syscall{work, doneCh}
- <-doneCh
-}
-
-func (p *syscallPool) shutdown() {
- for _, ch := range p.shutdownCh {
- ch <- struct{}{} // Blocks until the value is received
- }
-}
-
-func (p *syscallPool) worker(shutdownCh <-chan struct{}) {
- for {
- select {
- case <-shutdownCh:
- return
- case work := <-p.workCh:
- work.work()
- work.done <- struct{}{}
- }
- }
-}
-
// Ensures that the node for the given path exists in the tree and returns it.
func ensureNodeExists(root *instructionsNode, path string) *instructionsNode {
if path == "" {
@@ -171,25 +117,13 @@ func mergeBuildFiles(output string, srcBuildFile string, generatedBuildFile stri
generatedBuildFileContent = packageDefaultVisibilityRegex.ReplaceAll(generatedBuildFileContent, []byte{})
}
- outFile, err := os.Create(output)
- if err != nil {
- return err
- }
-
- _, err = outFile.Write(generatedBuildFileContent)
- if err != nil {
- return err
- }
-
- if generatedBuildFileContent[len(generatedBuildFileContent)-1] != '\n' {
- _, err = outFile.WriteString("\n")
- if err != nil {
- return err
- }
+ newContents := generatedBuildFileContent
+ if newContents[len(newContents)-1] != '\n' {
+ newContents = append(newContents, '\n')
}
+ newContents = append(newContents, srcBuildFileContent...)
- _, err = outFile.Write(srcBuildFileContent)
- return err
+ return pathtools.WriteFileIfChanged(output, newContents, 0666)
}
// Calls readdir() and returns it as a map from the basename of the files in dir
@@ -217,12 +151,35 @@ func readdirToMap(dir string) map[string]os.FileInfo {
}
// Creates a symbolic link at dst pointing to src
-func symlinkIntoForest(topdir, dst, src string) {
- err := os.Symlink(shared.JoinPath(topdir, src), shared.JoinPath(topdir, dst))
- if err != nil {
+func symlinkIntoForest(topdir, dst, src string) uint64 {
+ srcPath := shared.JoinPath(topdir, src)
+ dstPath := shared.JoinPath(topdir, dst)
+
+ // Check if a symlink already exists.
+ if dstInfo, err := os.Lstat(dstPath); err != nil {
+ if !os.IsNotExist(err) {
+ fmt.Fprintf(os.Stderr, "Failed to lstat '%s': %s", dst, err)
+ os.Exit(1)
+ }
+ } else {
+ if dstInfo.Mode()&os.ModeSymlink != 0 {
+ // Assume that the link's target is correct, i.e. no manual tampering.
+ // E.g. OUT_DIR could have been previously used with a different source tree check-out!
+ return 0
+ } else {
+ if err := os.RemoveAll(dstPath); err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to remove '%s': %s", dst, err)
+ os.Exit(1)
+ }
+ }
+ }
+
+ // Create symlink.
+ if err := os.Symlink(srcPath, dstPath); err != nil {
fmt.Fprintf(os.Stderr, "Cannot create symlink at '%s' pointing to '%s': %s", dst, src, err)
os.Exit(1)
}
+ return 1
}
func isDir(path string, fi os.FileInfo) bool {
@@ -253,8 +210,9 @@ func plantSymlinkForestRecursive(context *symlinkForestContext, instructions *in
defer context.wg.Done()
if instructions != nil && instructions.excluded {
- // This directory is not needed, bail out
- return
+ // Excluded paths are skipped at the level of the non-excluded parent.
+ fmt.Fprintf(os.Stderr, "may not specify a root-level exclude directory '%s'", srcDir)
+ os.Exit(1)
}
// We don't add buildFilesDir here because the bp2build files marker files is
@@ -272,6 +230,12 @@ func plantSymlinkForestRecursive(context *symlinkForestContext, instructions *in
renamingBuildFile = true
srcDirMap["BUILD.bazel"] = srcDirMap["BUILD"]
delete(srcDirMap, "BUILD")
+ if instructions != nil {
+ if _, ok := instructions.children["BUILD"]; ok {
+ instructions.children["BUILD.bazel"] = instructions.children["BUILD"]
+ delete(instructions.children, "BUILD")
+ }
+ }
}
}
}
@@ -288,17 +252,41 @@ func plantSymlinkForestRecursive(context *symlinkForestContext, instructions *in
// Tests read the error messages generated, so ensure their order is deterministic
sort.Strings(allEntries)
- err := os.MkdirAll(shared.JoinPath(context.topdir, forestDir), 0777)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Cannot mkdir '%s': %s\n", forestDir, err)
- os.Exit(1)
+ fullForestPath := shared.JoinPath(context.topdir, forestDir)
+ createForestDir := false
+ if fi, err := os.Lstat(fullForestPath); err != nil {
+ if os.IsNotExist(err) {
+ createForestDir = true
+ } else {
+ fmt.Fprintf(os.Stderr, "Could not read info for '%s': %s\n", forestDir, err)
+ }
+ } else if fi.Mode()&os.ModeDir == 0 {
+ if err := os.RemoveAll(fullForestPath); err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to remove '%s': %s", forestDir, err)
+ os.Exit(1)
+ }
+ createForestDir = true
+ }
+ if createForestDir {
+ if err := os.MkdirAll(fullForestPath, 0777); err != nil {
+ fmt.Fprintf(os.Stderr, "Could not mkdir '%s': %s\n", forestDir, err)
+ os.Exit(1)
+ }
+ context.mkdirCount.Add(1)
}
- context.mkdirCount.Add(1)
+
+ // Start with a list of items that already exist in the forest, and remove
+ // each element as it is processed in allEntries. Any remaining items in
+ // forestMapForDeletion must be removed. (This handles files which were
+ // removed since the previous forest generation).
+ forestMapForDeletion := readdirToMap(shared.JoinPath(context.topdir, forestDir))
for _, f := range allEntries {
if f[0] == '.' {
continue // Ignore dotfiles
}
+ delete(forestMapForDeletion, f)
+ // todo add deletionCount metric
// The full paths of children in the input trees and in the output tree
forestChild := shared.JoinPath(forestDir, f)
@@ -309,13 +297,9 @@ func plantSymlinkForestRecursive(context *symlinkForestContext, instructions *in
buildFilesChild := shared.JoinPath(buildFilesDir, f)
// Descend in the instruction tree if it exists
- var instructionsChild *instructionsNode = nil
+ var instructionsChild *instructionsNode
if instructions != nil {
- if f == "BUILD.bazel" && renamingBuildFile {
- instructionsChild = instructions.children["BUILD"]
- } else {
- instructionsChild = instructions.children[f]
- }
+ instructionsChild = instructions.children[f]
}
srcChildEntry, sExists := srcDirMap[f]
@@ -323,8 +307,7 @@ func plantSymlinkForestRecursive(context *symlinkForestContext, instructions *in
if instructionsChild != nil && instructionsChild.excluded {
if bExists {
- symlinkIntoForest(context.topdir, forestChild, buildFilesChild)
- context.symlinkCount.Add(1)
+ context.symlinkCount.Add(symlinkIntoForest(context.topdir, forestChild, buildFilesChild))
}
continue
}
@@ -340,8 +323,7 @@ func plantSymlinkForestRecursive(context *symlinkForestContext, instructions *in
go plantSymlinkForestRecursive(context, instructionsChild, forestChild, buildFilesChild, srcChild)
} else {
// Not in the source tree, symlink BUILD file
- symlinkIntoForest(context.topdir, forestChild, buildFilesChild)
- context.symlinkCount.Add(1)
+ context.symlinkCount.Add(symlinkIntoForest(context.topdir, forestChild, buildFilesChild))
}
} else if !bExists {
if sDir && instructionsChild != nil {
@@ -351,8 +333,7 @@ func plantSymlinkForestRecursive(context *symlinkForestContext, instructions *in
go plantSymlinkForestRecursive(context, instructionsChild, forestChild, buildFilesChild, srcChild)
} else {
// Not in the build file tree, symlink source tree, carry on
- symlinkIntoForest(context.topdir, forestChild, srcChild)
- context.symlinkCount.Add(1)
+ context.symlinkCount.Add(symlinkIntoForest(context.topdir, forestChild, srcChild))
}
} else if sDir && bDir {
// Both are directories. Descend.
@@ -365,8 +346,7 @@ func plantSymlinkForestRecursive(context *symlinkForestContext, instructions *in
// The Android.bp file that codegen used to produce `buildFilesChild` is
// already a dependency, we can ignore `buildFilesChild`.
context.depCh <- srcChild
- err = mergeBuildFiles(shared.JoinPath(context.topdir, forestChild), srcBuildFile, generatedBuildFile, context.verbose)
- if err != nil {
+ if err := mergeBuildFiles(shared.JoinPath(context.topdir, forestChild), srcBuildFile, generatedBuildFile, context.verbose); err != nil {
fmt.Fprintf(os.Stderr, "Error merging %s and %s: %s",
srcBuildFile, generatedBuildFile, err)
os.Exit(1)
@@ -379,51 +359,27 @@ func plantSymlinkForestRecursive(context *symlinkForestContext, instructions *in
os.Exit(1)
}
}
-}
-func removeParallelRecursive(pool *syscallPool, path string, fi os.FileInfo, wg *sync.WaitGroup) {
- defer wg.Done()
-
- if fi.IsDir() {
- children := readdirToMap(path)
- childrenWg := &sync.WaitGroup{}
- childrenWg.Add(len(children))
-
- for child, childFi := range children {
- go removeParallelRecursive(pool, shared.JoinPath(path, child), childFi, childrenWg)
+ // Remove all files in the forest that exist in neither the source
+ // tree nor the build files tree. (This handles files which were removed
+ // since the previous forest generation).
+ for f := range forestMapForDeletion {
+ var instructionsChild *instructionsNode
+ if instructions != nil {
+ instructionsChild = instructions.children[f]
}
- childrenWg.Wait()
- }
-
- pool.do(func() {
- if err := os.Remove(path); err != nil {
- fmt.Fprintf(os.Stderr, "Cannot unlink '%s': %s\n", path, err)
- os.Exit(1)
+ if instructionsChild != nil && instructionsChild.excluded {
+ // This directory may be excluded because bazel writes to it under the
+ // forest root. Thus this path is intentionally left alone.
+ continue
}
- })
-}
-
-func removeParallel(path string) {
- fi, err := os.Lstat(path)
- if err != nil {
- if errors.Is(err, fs.ErrNotExist) {
- return
+ forestChild := shared.JoinPath(context.topdir, forestDir, f)
+ if err := os.RemoveAll(forestChild); err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to remove '%s/%s': %s", forestDir, f, err)
+ os.Exit(1)
}
-
- fmt.Fprintf(os.Stderr, "Cannot lstat '%s': %s\n", path, err)
- os.Exit(1)
}
-
- wg := &sync.WaitGroup{}
- wg.Add(1)
-
- // Random guess as to the best number of syscalls to run in parallel
- pool := createSyscallPool(100)
- removeParallelRecursive(pool, path, fi, wg)
- pool.shutdown()
-
- wg.Wait()
}
// PlantSymlinkForest Creates a symlink forest by merging the directory tree at "buildFiles" and
@@ -439,8 +395,6 @@ func PlantSymlinkForest(verbose bool, topdir string, forest string, buildFiles s
symlinkCount: atomic.Uint64{},
}
- removeParallel(shared.JoinPath(topdir, forest))
-
instructions := instructionsFromExcludePathList(exclude)
go func() {
context.wg.Add(1)
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 92a9bf1b5..43baf98db 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -230,11 +230,11 @@ func (b BazelTestResult) CompareAllBazelTargets(t *testing.T, description string
actualTargets := b.buildFileToTargets
// Generate the sorted set of directories to check.
- dirsToCheck := android.SortedStringKeys(expectedTargets)
+ dirsToCheck := android.SortedKeys(expectedTargets)
if !ignoreUnexpected {
// This needs to perform an exact match so add the directories in which targets were
// produced to the list of directories to check.
- dirsToCheck = append(dirsToCheck, android.SortedStringKeys(actualTargets)...)
+ dirsToCheck = append(dirsToCheck, android.SortedKeys(actualTargets)...)
dirsToCheck = android.SortedUniqueStrings(dirsToCheck)
}
@@ -579,7 +579,7 @@ func makeBazelTargetHostOrDevice(typ, name string, attrs AttrNameToString, hod a
if name != "" {
attrStrings = append(attrStrings, fmt.Sprintf(` name = "%s",`, name))
}
- for _, k := range android.SortedStringKeys(attrs) {
+ for _, k := range android.SortedKeys(attrs) {
attrStrings = append(attrStrings, fmt.Sprintf(" %s = %s,", k, attrs[k]))
}
return fmt.Sprintf(`%s(
diff --git a/cc/OWNERS b/cc/OWNERS
index ffbf14abe..c4d82d254 100644
--- a/cc/OWNERS
+++ b/cc/OWNERS
@@ -1,4 +1 @@
per-file ndk_*.go = danalbert@google.com
-per-file tidy*.go = srhines@google.com, chh@google.com
-per-file afdo.go,afdo_test.go,lto.go,pgo.go = srhines@google.com, pirama@google.com, yikong@google.com
-per-file coverage.go = pirama@google.com, srhines@google.com, allenhair@google.com
diff --git a/cc/androidmk.go b/cc/androidmk.go
index ce35b5c44..980dd0762 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -124,14 +124,17 @@ func (c *Module) AndroidMkEntries() []android.AndroidMkEntries {
}
}
}
- if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake {
+ if c.Properties.IsSdkVariant {
// Make the SDK variant uninstallable so that there are not two rules to install
// to the same location.
entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
- // Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite
- // dependencies to the .sdk suffix when building a module that uses the SDK.
- entries.SetString("SOONG_SDK_VARIANT_MODULES",
- "$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))")
+
+ if c.Properties.SdkAndPlatformVariantVisibleToMake {
+ // Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite
+ // dependencies to the .sdk suffix when building a module that uses the SDK.
+ entries.SetString("SOONG_SDK_VARIANT_MODULES",
+ "$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))")
+ }
}
},
},
diff --git a/cc/binary.go b/cc/binary.go
index 2f8ee7ff1..496c610c2 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -151,7 +151,7 @@ func (binary *binaryDecorator) getStem(ctx BaseModuleContext) string {
// modules common to most binaries, such as bionic libraries.
func (binary *binaryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
deps = binary.baseLinker.linkerDeps(ctx, deps)
- if !Bool(binary.baseLinker.Properties.Nocrt) {
+ if binary.baseLinker.Properties.crt() {
if binary.static() {
deps.CrtBegin = ctx.toolchain().CrtBeginStaticBinary()
deps.CrtEnd = ctx.toolchain().CrtEndStaticBinary()
@@ -577,18 +577,22 @@ var _ BazelHandler = (*ccBinaryBazelHandler)(nil)
func (handler *ccBinaryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
bazelCtx := ctx.Config().BazelContext
- bazelCtx.QueueBazelRequest(label, cquery.GetCcUnstrippedInfo, android.GetConfigKey(ctx))
+ bazelCtx.QueueBazelRequest(label, cquery.GetCcUnstrippedInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
}
func (handler *ccBinaryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
bazelCtx := ctx.Config().BazelContext
- info, err := bazelCtx.GetCcUnstrippedInfo(label, android.GetConfigKey(ctx))
+ info, err := bazelCtx.GetCcUnstrippedInfo(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
if err != nil {
ctx.ModuleErrorf(err.Error())
return
}
- outputFilePath := android.PathForBazelOut(ctx, info.OutputFile)
+ var outputFilePath android.Path = android.PathForBazelOut(ctx, info.OutputFile)
+ if len(info.TidyFiles) > 0 {
+ handler.module.tidyFiles = android.PathsForBazelOut(ctx, info.TidyFiles)
+ outputFilePath = android.AttachValidationActions(ctx, outputFilePath, handler.module.tidyFiles)
+ }
handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
handler.module.linker.(*binaryDecorator).unstrippedOutputFile = android.PathForBazelOut(ctx, info.UnstrippedOutput)
@@ -626,8 +630,6 @@ func binaryBp2buildAttrs(ctx android.TopDownMutatorContext, m *Module) binaryAtt
Local_includes: baseAttrs.localIncludes,
Absolute_includes: baseAttrs.absoluteIncludes,
Linkopts: baseAttrs.linkopts,
- Link_crt: baseAttrs.linkCrt,
- Use_libcrt: baseAttrs.useLibcrt,
Use_version_lib: baseAttrs.useVersionLib,
Rtti: baseAttrs.rtti,
Stl: baseAttrs.stl,
@@ -691,10 +693,7 @@ type binaryAttributes struct {
Linkopts bazel.StringListAttribute
Additional_linker_inputs bazel.LabelListAttribute
-
- Link_crt bazel.BoolAttribute
- Use_libcrt bazel.BoolAttribute
- Use_version_lib bazel.BoolAttribute
+ Use_version_lib bazel.BoolAttribute
Rtti bazel.BoolAttribute
Stl *string
diff --git a/cc/binary_test.go b/cc/binary_test.go
index 43aff5c68..e0b5b5d20 100644
--- a/cc/binary_test.go
+++ b/cc/binary_test.go
@@ -55,6 +55,47 @@ cc_binary {
android.AssertStringEquals(t, "Unstripped output file", expectedUnStrippedFile, unStrippedFilePath.String())
}
+func TestCcBinaryWithBazelValidations(t *testing.T) {
+ t.Parallel()
+ bp := `
+cc_binary {
+ name: "foo",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo/bar:bar" },
+ tidy: true,
+}`
+ config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: "outputbase",
+ LabelToCcBinary: map[string]cquery.CcUnstrippedInfo{
+ "//foo/bar:bar": cquery.CcUnstrippedInfo{
+ OutputFile: "foo",
+ UnstrippedOutput: "foo.unstripped",
+ TidyFiles: []string{"foo.c.tidy"},
+ },
+ },
+ }
+ ctx := android.GroupFixturePreparers(
+ prepareForCcTest,
+ android.FixtureMergeEnv(map[string]string{
+ "ALLOW_LOCAL_TIDY_TRUE": "1",
+ }),
+ ).RunTestWithConfig(t, config).TestContext
+
+ binMod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module()
+ producer := binMod.(android.OutputFileProducer)
+ outputFiles, err := producer.OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_binary outputfiles %s", err)
+ }
+ expectedOutputFiles := []string{"out/soong/.intermediates/foo/android_arm64_armv8-a/validated/foo"}
+ android.AssertPathsRelativeToTopEquals(t, "output files", expectedOutputFiles, outputFiles)
+
+ unStrippedFilePath := binMod.(*Module).UnstrippedOutputFile()
+ expectedUnStrippedFile := "outputbase/execroot/__main__/foo.unstripped"
+ android.AssertStringEquals(t, "Unstripped output file", expectedUnStrippedFile, unStrippedFilePath.String())
+}
+
func TestBinaryLinkerScripts(t *testing.T) {
t.Parallel()
result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, `
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 6c5505a6e..9751a2eee 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -965,8 +965,6 @@ type linkerAttributes struct {
systemDynamicDeps bazel.LabelListAttribute
usedSystemDynamicDepAsDynamicDep map[string]bool
- linkCrt bazel.BoolAttribute
- useLibcrt bazel.BoolAttribute
useVersionLib bazel.BoolAttribute
linkopts bazel.StringListAttribute
additionalLinkerInputs bazel.LabelListAttribute
@@ -1082,43 +1080,13 @@ func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversion
la.resolveTargetApexProp(ctx, props)
if axis == bazel.NoConfigAxis || (axis == bazel.OsConfigurationAxis && config == bazel.OsAndroid) {
- // If a dependency in la.implementationDynamicDeps has stubs, its stub variant should be
- // used when the dependency is linked in a APEX. The dependencies in NoConfigAxis and
- // OsConfigurationAxis/OsAndroid are grouped by having stubs or not, so Bazel select()
- // statement can be used to choose source/stub variants of them.
- depsWithStubs := []bazel.Label{}
- for _, l := range sharedDeps.implementation.Includes {
- dep, _ := ctx.ModuleFromName(l.OriginalModuleName)
- if m, ok := dep.(*Module); ok && m.HasStubsVariants() {
- depsWithStubs = append(depsWithStubs, l)
- }
- }
- if len(depsWithStubs) > 0 {
- implDynamicDeps := bazel.SubtractBazelLabelList(sharedDeps.implementation, bazel.MakeLabelList(depsWithStubs))
- la.implementationDynamicDeps.SetSelectValue(axis, config, implDynamicDeps)
-
- stubLibLabels := []bazel.Label{}
- for _, l := range depsWithStubs {
- l.Label = l.Label + stubsSuffix
- stubLibLabels = append(stubLibLabels, l)
- }
- inApexSelectValue := la.implementationDynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex)
- nonApexSelectValue := la.implementationDynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex)
- defaultSelectValue := la.implementationDynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey)
- if axis == bazel.NoConfigAxis {
- (&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels))
- (&nonApexSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
- (&defaultSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
- la.implementationDynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue))
- la.implementationDynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
- la.implementationDynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.FirstUniqueBazelLabelList(defaultSelectValue))
- } else if config == bazel.OsAndroid {
- (&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels))
- (&nonApexSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
- la.implementationDynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue))
- la.implementationDynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
- }
- }
+ // If a dependency in la.implementationDynamicDeps or la.dynamicDeps has stubs, its
+ // stub variant should be used when the dependency is linked in a APEX. The
+ // dependencies in NoConfigAxis and OsConfigurationAxis/OsAndroid are grouped by
+ // having stubs or not, so Bazel select() statement can be used to choose
+ // source/stub variants of them.
+ setStubsForDynamicDeps(ctx, axis, config, sharedDeps.export, &la.dynamicDeps, 0)
+ setStubsForDynamicDeps(ctx, axis, config, sharedDeps.implementation, &la.implementationDynamicDeps, 1)
}
if !BoolDefault(props.Pack_relocations, packRelocationsDefault) {
@@ -1138,6 +1106,13 @@ func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversion
}
}
+ if !props.libCrt() {
+ axisFeatures = append(axisFeatures, "-use_libcrt")
+ }
+ if !props.crt() {
+ axisFeatures = append(axisFeatures, "-link_crt")
+ }
+
// This must happen before the addition of flags for Version Script and
// Dynamic List, as these flags must be split on spaces and those must not
linkerFlags = parseCommandLineFlags(linkerFlags, filterOutClangUnknownCflags)
@@ -1157,16 +1132,6 @@ func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversion
la.additionalLinkerInputs.SetSelectValue(axis, config, additionalLinkerInputs)
la.linkopts.SetSelectValue(axis, config, linkerFlags)
- la.useLibcrt.SetSelectValue(axis, config, props.libCrt())
-
- // it's very unlikely for nocrt to be arch variant, so bp2build doesn't support it.
- if props.crt() != nil {
- if axis == bazel.NoConfigAxis {
- la.linkCrt.SetSelectValue(axis, config, props.crt())
- } else if axis == bazel.ArchConfigurationAxis {
- ctx.ModuleErrorf("nocrt is not supported for arch variants")
- }
- }
if axisFeatures != nil {
la.features.SetSelectValue(axis, config, axisFeatures)
@@ -1178,6 +1143,43 @@ func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversion
}
}
+func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis,
+ config string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int) {
+ depsWithStubs := []bazel.Label{}
+ for _, l := range dynamicLibs.Includes {
+ dep, _ := ctx.ModuleFromName(l.OriginalModuleName)
+ if m, ok := dep.(*Module); ok && m.HasStubsVariants() {
+ depsWithStubs = append(depsWithStubs, l)
+ }
+ }
+ if len(depsWithStubs) > 0 {
+ implDynamicDeps := bazel.SubtractBazelLabelList(dynamicLibs, bazel.MakeLabelList(depsWithStubs))
+ dynamicDeps.SetSelectValue(axis, config, implDynamicDeps)
+
+ stubLibLabels := []bazel.Label{}
+ for _, l := range depsWithStubs {
+ l.Label = l.Label + stubsSuffix
+ stubLibLabels = append(stubLibLabels, l)
+ }
+ inApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex)
+ nonApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex)
+ defaultSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey)
+ if axis == bazel.NoConfigAxis {
+ (&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels))
+ (&nonApexSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
+ (&defaultSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
+ dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue))
+ dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
+ dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.FirstUniqueBazelLabelList(defaultSelectValue))
+ } else if config == bazel.OsAndroid {
+ (&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels))
+ (&nonApexSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
+ dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue))
+ dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
+ }
+ }
+}
+
func (la *linkerAttributes) convertStripProps(ctx android.BazelConversionPathContext, module *Module) {
bp2BuildPropParseHelper(ctx, module, &StripProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
if stripProperties, ok := props.(*StripProperties); ok {
@@ -1261,7 +1263,7 @@ func (la *linkerAttributes) finalize(ctx android.BazelConversionPathContext) {
// result in duplicate library errors for bionic OSes. Here, we explicitly exclude those libraries
// from bionic OSes and the no config case as these libraries only build for bionic OSes.
if la.systemDynamicDeps.IsNil() && len(la.usedSystemDynamicDepAsDynamicDep) > 0 {
- toRemove := bazelLabelForSharedDeps(ctx, android.SortedStringKeys(la.usedSystemDynamicDepAsDynamicDep))
+ toRemove := bazelLabelForSharedDeps(ctx, android.SortedKeys(la.usedSystemDynamicDepAsDynamicDep))
la.dynamicDeps.Exclude(bazel.NoConfigAxis, "", toRemove)
la.dynamicDeps.Exclude(bazel.OsConfigurationAxis, "android", toRemove)
la.dynamicDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove)
diff --git a/cc/cc.go b/cc/cc.go
index c33c5e3cc..c07d836a6 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1066,6 +1066,31 @@ func (c *Module) CcLibraryInterface() bool {
return false
}
+func (c *Module) IsFuzzModule() bool {
+ if _, ok := c.compiler.(*fuzzBinary); ok {
+ return true
+ }
+ return false
+}
+
+func (c *Module) FuzzModuleStruct() fuzz.FuzzModule {
+ return c.FuzzModule
+}
+
+func (c *Module) FuzzPackagedModule() fuzz.FuzzPackagedModule {
+ if fuzzer, ok := c.compiler.(*fuzzBinary); ok {
+ return fuzzer.fuzzPackagedModule
+ }
+ panic(fmt.Errorf("FuzzPackagedModule called on non-fuzz module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) FuzzSharedLibraries() android.Paths {
+ if fuzzer, ok := c.compiler.(*fuzzBinary); ok {
+ return fuzzer.sharedLibraries
+ }
+ panic(fmt.Errorf("FuzzSharedLibraries called on non-fuzz module: %q", c.BaseModuleName()))
+}
+
func (c *Module) NonCcVariants() bool {
return false
}
@@ -1880,20 +1905,36 @@ func (c *Module) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
}
// TODO(b/261058727): Remove this (enable mixed builds for modules with UBSan)
- ubsanEnabled := c.sanitize != nil &&
- ((c.sanitize.Properties.Sanitize.Integer_overflow != nil && *c.sanitize.Properties.Sanitize.Integer_overflow) ||
- c.sanitize.Properties.Sanitize.Misc_undefined != nil)
- return c.bazelHandler != nil && !ubsanEnabled
+ // Currently we can only support ubsan when minimum runtime is used.
+ return c.bazelHandler != nil && (!isUbsanEnabled(c) || c.MinimalRuntimeNeeded())
}
-func (c *Module) ProcessBazelQueryResponse(ctx android.ModuleContext) {
- bazelModuleLabel := c.getBazelModuleLabel(ctx)
+func isUbsanEnabled(c *Module) bool {
+ if c.sanitize == nil {
+ return false
+ }
+ sanitizeProps := &c.sanitize.Properties.SanitizeMutated
+ return Bool(sanitizeProps.Integer_overflow) || len(sanitizeProps.Misc_undefined) > 0
+}
- bazelCtx := ctx.Config().BazelContext
- if ccInfo, err := bazelCtx.GetCcInfo(bazelModuleLabel, android.GetConfigKey(ctx)); err == nil {
- c.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles)
+func GetApexConfigKey(ctx android.BaseModuleContext) *android.ApexConfigKey {
+ apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ if !apexInfo.IsForPlatform() {
+ if !ctx.Config().BazelContext.IsModuleDclaAllowed(ctx.Module().Name()) {
+ return nil
+ }
+ apexKey := android.ApexConfigKey{
+ WithinApex: true,
+ ApexSdkVersion: findApexSdkVersion(ctx, apexInfo).String(),
+ }
+ return &apexKey
}
+ return nil
+}
+
+func (c *Module) ProcessBazelQueryResponse(ctx android.ModuleContext) {
+ bazelModuleLabel := c.getBazelModuleLabel(ctx)
c.bazelHandler.ProcessBazelQueryResponse(ctx, bazelModuleLabel)
c.Properties.SubName = GetSubnameProperty(ctx, c)
@@ -2822,6 +2863,23 @@ func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) {
}
}
+func findApexSdkVersion(ctx android.BaseModuleContext, apexInfo android.ApexInfo) android.ApiLevel {
+ // For the dependency from platform to apex, use the latest stubs
+ apexSdkVersion := android.FutureApiLevel
+ if !apexInfo.IsForPlatform() {
+ apexSdkVersion = apexInfo.MinSdkVersion
+ }
+
+ if android.InList("hwaddress", ctx.Config().SanitizeDevice()) {
+ // In hwasan build, we override apexSdkVersion to the FutureApiLevel(10000)
+ // so that even Q(29/Android10) apexes could use the dynamic unwinder by linking the newer stubs(e.g libc(R+)).
+ // (b/144430859)
+ apexSdkVersion = android.FutureApiLevel
+ }
+
+ return apexSdkVersion
+}
+
// Convert dependencies to paths. Returns a PathDeps containing paths
func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
var depPaths PathDeps
@@ -2837,19 +2895,8 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
depPaths.ReexportedGeneratedHeaders = append(depPaths.ReexportedGeneratedHeaders, exporter.GeneratedHeaders...)
}
- // For the dependency from platform to apex, use the latest stubs
- c.apexSdkVersion = android.FutureApiLevel
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
- if !apexInfo.IsForPlatform() {
- c.apexSdkVersion = apexInfo.MinSdkVersion
- }
-
- if android.InList("hwaddress", ctx.Config().SanitizeDevice()) {
- // In hwasan build, we override apexSdkVersion to the FutureApiLevel(10000)
- // so that even Q(29/Android10) apexes could use the dynamic unwinder by linking the newer stubs(e.g libc(R+)).
- // (b/144430859)
- c.apexSdkVersion = android.FutureApiLevel
- }
+ c.apexSdkVersion = findApexSdkVersion(ctx, apexInfo)
ctx.VisitDirectDeps(func(dep android.Module) {
depName := ctx.OtherModuleName(dep)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 62adfd3ae..b02e037ed 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -28,6 +28,10 @@ import (
"android/soong/bazel/cquery"
)
+func init() {
+ registerTestMutators(android.InitRegistrationContext)
+}
+
func TestMain(m *testing.M) {
os.Exit(m.Run())
}
@@ -41,6 +45,36 @@ var prepareForCcTest = android.GroupFixturePreparers(
}),
)
+var ccLibInApex = "cc_lib_in_apex"
+var apexVariationName = "apex28"
+var apexVersion = "28"
+
+func registerTestMutators(ctx android.RegistrationContext) {
+ ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("apex", testApexMutator).Parallel()
+ ctx.BottomUp("mixed_builds_prep", mixedBuildsPrepareMutator).Parallel()
+ })
+}
+
+func mixedBuildsPrepareMutator(ctx android.BottomUpMutatorContext) {
+ if m := ctx.Module(); m.Enabled() {
+ if mixedBuildMod, ok := m.(android.MixedBuildBuildable); ok {
+ if mixedBuildMod.IsMixedBuildSupported(ctx) && android.MixedBuildsEnabled(ctx) {
+ mixedBuildMod.QueueBazelCall(ctx)
+ }
+ }
+ }
+}
+
+func testApexMutator(mctx android.BottomUpMutatorContext) {
+ modules := mctx.CreateVariations(apexVariationName)
+ apexInfo := android.ApexInfo{
+ ApexVariationName: apexVariationName,
+ MinSdkVersion: android.ApiLevelForTest(apexVersion),
+ }
+ mctx.SetVariationProvider(modules[0], android.ApexInfoProvider, apexInfo)
+}
+
// testCcWithConfig runs tests using the prepareForCcTest
//
// See testCc for an explanation as to how to stop using this deprecated method.
@@ -3896,7 +3930,7 @@ func assertArrayString(t *testing.T, got, expected []string) {
func assertMapKeys(t *testing.T, m map[string]string, expected []string) {
t.Helper()
- assertArrayString(t, android.SortedStringKeys(m), expected)
+ assertArrayString(t, android.SortedKeys(m), expected)
}
func TestDefaults(t *testing.T) {
@@ -4906,3 +4940,56 @@ func TestCcBuildBrokenClangCFlags(t *testing.T) {
})
}
}
+
+func TestDclaLibraryInApex(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library_shared {
+ name: "cc_lib_in_apex",
+ srcs: ["foo.cc"],
+ apex_available: ["myapex"],
+ bazel_module: { label: "//foo/bar:bar" },
+ }`
+ label := "//foo/bar:bar"
+ arch64 := "arm64_armv8-a"
+ arch32 := "arm_armv7-a-neon"
+ apexCfgKey := android.ApexConfigKey{
+ WithinApex: true,
+ ApexSdkVersion: "28",
+ }
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ android.FixtureRegisterWithContext(registerTestMutators),
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: "outputbase",
+ LabelToCcInfo: map[string]cquery.CcInfo{
+ android.BuildMockBazelContextResultKey(label, arch32, android.Android, apexCfgKey): cquery.CcInfo{
+ RootDynamicLibraries: []string{"foo.so"},
+ },
+ android.BuildMockBazelContextResultKey(label, arch64, android.Android, apexCfgKey): cquery.CcInfo{
+ RootDynamicLibraries: []string{"foo.so"},
+ },
+ },
+ BazelRequests: make(map[string]bool),
+ }
+ }),
+ ).RunTestWithBp(t, bp)
+ ctx := result.TestContext
+
+ // Test if the bazel request is queued correctly
+ key := android.BuildMockBazelContextRequestKey(label, cquery.GetCcInfo, arch32, android.Android, apexCfgKey)
+ if !ctx.Config().BazelContext.(android.MockBazelContext).BazelRequests[key] {
+ t.Errorf("Bazel request was not queued: %s", key)
+ }
+
+ sharedFoo := ctx.ModuleForTests(ccLibInApex, "android_arm_armv7-a-neon_shared_"+apexVariationName).Module()
+ producer := sharedFoo.(android.OutputFileProducer)
+ outputFiles, err := producer.OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+ }
+ expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.so"}
+ android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
+}
diff --git a/cc/config/global.go b/cc/config/global.go
index d557c0b01..05dc77354 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -207,10 +207,7 @@ var (
"-Werror=fortify-source",
"-Werror=address-of-temporary",
- // Bug: http://b/29823425 Disable -Wnull-dereference until the
- // new cases detected by this warning in Clang r271374 are
- // fixed.
- //"-Werror=null-dereference",
+ "-Werror=null-dereference",
"-Werror=return-type",
// http://b/72331526 Disable -Wtautological-* until the instances detected by these
@@ -250,16 +247,11 @@ var (
noOverride64GlobalCflags = []string{}
noOverrideExternalGlobalCflags = []string{
- // http://b/148815709
"-Wno-sizeof-array-div",
- // http://b/197240255
"-Wno-unused-but-set-variable",
"-Wno-unused-but-set-parameter",
- // http://b/215753485
"-Wno-bitwise-instead-of-logical",
- // http://b/232926688
"-Wno-misleading-indentation",
- // http://b/241941550
"-Wno-array-parameter",
}
@@ -279,7 +271,6 @@ var (
// http://b/145211477
"-Wno-pointer-compare",
- // http://b/145211022
"-Wno-final-dtor-non-final-class",
// http://b/165945989
@@ -293,6 +284,9 @@ var (
// http://b/239661264
"-Wno-deprecated-non-prototype",
+
+ // http://b/191699019
+ "-Wno-format-insufficient-args",
}
llvmNextExtraCommonGlobalCflags = []string{
@@ -432,7 +426,7 @@ func init() {
pctx.StaticVariable("ClangBin", "${ClangPath}/bin")
pctx.StaticVariableWithEnvOverride("ClangShortVersion", "LLVM_RELEASE_VERSION", ClangDefaultShortVersion)
- pctx.StaticVariable("ClangAsanLibDir", "${ClangBase}/linux-x86/${ClangVersion}/lib64/clang/${ClangShortVersion}/lib/linux")
+ pctx.StaticVariable("ClangAsanLibDir", "${ClangBase}/linux-x86/${ClangVersion}/lib/clang/${ClangShortVersion}/lib/linux")
// These are tied to the version of LLVM directly in external/llvm, so they might trail the host prebuilts
// being used for the rest of the build process.
diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go
index 67208b261..b3619c861 100644
--- a/cc/config/riscv64_device.go
+++ b/cc/config/riscv64_device.go
@@ -35,7 +35,9 @@ var (
}
riscv64Lldflags = append(riscv64Ldflags,
- "-Wl,-z,max-page-size=4096")
+ "-Wl,-z,max-page-size=4096",
+ "-Wl,-plugin-opt,-emulated-tls=0",
+ )
riscv64Cppflags = []string{}
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 7113d87df..7aa8b91c7 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -212,7 +212,7 @@ func IsValidSharedDependency(dependency android.Module) bool {
return true
}
-func sharedLibraryInstallLocation(
+func SharedLibraryInstallLocation(
libraryPath android.Path, isHost bool, fuzzDir string, archString string) string {
installLocation := "$(PRODUCT_OUT)/data"
if isHost {
@@ -224,7 +224,7 @@ func sharedLibraryInstallLocation(
}
// Get the device-only shared library symbols install directory.
-func sharedLibrarySymbolsInstallLocation(libraryPath android.Path, fuzzDir string, archString string) string {
+func SharedLibrarySymbolsInstallLocation(libraryPath android.Path, fuzzDir string, archString string) string {
return filepath.Join("$(PRODUCT_OUT)/symbols/data/", fuzzDir, archString, "/lib/", libraryPath.Base())
}
@@ -237,57 +237,62 @@ func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) {
installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
fuzzBin.binaryDecorator.baseInstaller.install(ctx, file)
- fuzzBin.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzzBin.fuzzPackagedModule.FuzzProperties.Corpus)
+ fuzzBin.fuzzPackagedModule = PackageFuzzModule(ctx, fuzzBin.fuzzPackagedModule, pctx)
+
+ // Grab the list of required shared libraries.
+ fuzzBin.sharedLibraries, _ = CollectAllSharedDependencies(ctx)
+
+ for _, lib := range fuzzBin.sharedLibraries {
+ fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
+ SharedLibraryInstallLocation(
+ lib, ctx.Host(), installBase, ctx.Arch().ArchType.String()))
+
+ // Also add the dependency on the shared library symbols dir.
+ if !ctx.Host() {
+ fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
+ SharedLibrarySymbolsInstallLocation(lib, installBase, ctx.Arch().ArchType.String()))
+ }
+ }
+}
+
+func PackageFuzzModule(ctx android.ModuleContext, fuzzPackagedModule fuzz.FuzzPackagedModule, pctx android.PackageContext) fuzz.FuzzPackagedModule {
+ fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Corpus)
builder := android.NewRuleBuilder(pctx, ctx)
intermediateDir := android.PathForModuleOut(ctx, "corpus")
- for _, entry := range fuzzBin.fuzzPackagedModule.Corpus {
+ for _, entry := range fuzzPackagedModule.Corpus {
builder.Command().Text("cp").
Input(entry).
Output(intermediateDir.Join(ctx, entry.Base()))
}
builder.Build("copy_corpus", "copy corpus")
- fuzzBin.fuzzPackagedModule.CorpusIntermediateDir = intermediateDir
+ fuzzPackagedModule.CorpusIntermediateDir = intermediateDir
- fuzzBin.fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzzBin.fuzzPackagedModule.FuzzProperties.Data)
+ fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Data)
builder = android.NewRuleBuilder(pctx, ctx)
intermediateDir = android.PathForModuleOut(ctx, "data")
- for _, entry := range fuzzBin.fuzzPackagedModule.Data {
+ for _, entry := range fuzzPackagedModule.Data {
builder.Command().Text("cp").
Input(entry).
Output(intermediateDir.Join(ctx, entry.Rel()))
}
builder.Build("copy_data", "copy data")
- fuzzBin.fuzzPackagedModule.DataIntermediateDir = intermediateDir
+ fuzzPackagedModule.DataIntermediateDir = intermediateDir
- if fuzzBin.fuzzPackagedModule.FuzzProperties.Dictionary != nil {
- fuzzBin.fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzzBin.fuzzPackagedModule.FuzzProperties.Dictionary)
- if fuzzBin.fuzzPackagedModule.Dictionary.Ext() != ".dict" {
+ if fuzzPackagedModule.FuzzProperties.Dictionary != nil {
+ fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzzPackagedModule.FuzzProperties.Dictionary)
+ if fuzzPackagedModule.Dictionary.Ext() != ".dict" {
ctx.PropertyErrorf("dictionary",
"Fuzzer dictionary %q does not have '.dict' extension",
- fuzzBin.fuzzPackagedModule.Dictionary.String())
+ fuzzPackagedModule.Dictionary.String())
}
}
- if fuzzBin.fuzzPackagedModule.FuzzProperties.Fuzz_config != nil {
+ if fuzzPackagedModule.FuzzProperties.Fuzz_config != nil {
configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json")
- android.WriteFileRule(ctx, configPath, fuzzBin.fuzzPackagedModule.FuzzProperties.Fuzz_config.String())
- fuzzBin.fuzzPackagedModule.Config = configPath
- }
-
- // Grab the list of required shared libraries.
- fuzzBin.sharedLibraries, _ = CollectAllSharedDependencies(ctx)
-
- for _, lib := range fuzzBin.sharedLibraries {
- fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
- sharedLibraryInstallLocation(
- lib, ctx.Host(), installBase, ctx.Arch().ArchType.String()))
-
- // Also add the dependency on the shared library symbols dir.
- if !ctx.Host() {
- fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
- sharedLibrarySymbolsInstallLocation(lib, installBase, ctx.Arch().ArchType.String()))
- }
+ android.WriteFileRule(ctx, configPath, fuzzPackagedModule.FuzzProperties.Fuzz_config.String())
+ fuzzPackagedModule.Config = configPath
}
+ return fuzzPackagedModule
}
func NewFuzzer(hod android.HostOrDeviceSupported) *Module {
@@ -344,7 +349,7 @@ func NewFuzzer(hod android.HostOrDeviceSupported) *Module {
// Responsible for generating GNU Make rules that package fuzz targets into
// their architecture & target/host specific zip file.
-type ccFuzzPackager struct {
+type ccRustFuzzPackager struct {
fuzz.FuzzPackager
fuzzPackagingArchModules string
fuzzTargetSharedDepsInstallPairs string
@@ -353,7 +358,7 @@ type ccFuzzPackager struct {
func fuzzPackagingFactory() android.Singleton {
- fuzzPackager := &ccFuzzPackager{
+ fuzzPackager := &ccRustFuzzPackager{
fuzzPackagingArchModules: "SOONG_FUZZ_PACKAGING_ARCH_MODULES",
fuzzTargetSharedDepsInstallPairs: "FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
allFuzzTargetsName: "ALL_FUZZ_TARGETS",
@@ -361,7 +366,7 @@ func fuzzPackagingFactory() android.Singleton {
return fuzzPackager
}
-func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
+func (s *ccRustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
// Map between each architecture + host/device combination, and the files that
// need to be packaged (in the tuple of {source file, destination folder in
// archive}).
@@ -376,19 +381,18 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
sharedLibraryInstalled := make(map[string]bool)
ctx.VisitAllModules(func(module android.Module) {
- ccModule, ok := module.(*Module)
- if !ok || ccModule.Properties.PreventInstall {
+ ccModule, ok := module.(LinkableInterface)
+ if !ok || ccModule.PreventInstall() {
return
}
// Discard non-fuzz targets.
- if ok := fuzz.IsValid(ccModule.FuzzModule); !ok {
+ if ok := fuzz.IsValid(ccModule.FuzzModuleStruct()); !ok {
return
}
sharedLibsInstallDirPrefix := "lib"
- fuzzModule, ok := ccModule.compiler.(*fuzzBinary)
- if !ok {
+ if !ccModule.IsFuzzModule() {
return
}
@@ -399,12 +403,12 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
fpm := fuzz.FuzzPackagedModule{}
if ok {
- fpm = fuzzModule.fuzzPackagedModule
+ fpm = ccModule.FuzzPackagedModule()
}
intermediatePath := "fuzz"
- archString := ccModule.Arch().ArchType.String()
+ archString := ccModule.Target().Arch.ArchType.String()
archDir := android.PathForIntermediates(ctx, intermediatePath, hostOrTargetString, archString)
archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
@@ -415,7 +419,7 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
files = s.PackageArtifacts(ctx, module, fpm, archDir, builder)
// Package shared libraries
- files = append(files, GetSharedLibsToZip(fuzzModule.sharedLibraries, ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...)
+ files = append(files, GetSharedLibsToZip(ccModule.FuzzSharedLibraries(), ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...)
// The executable.
files = append(files, fuzz.FileToZip{android.OutputFileForModule(ctx, ccModule, "unstripped"), ""})
@@ -429,7 +433,7 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
s.CreateFuzzPackage(ctx, archDirs, fuzz.Cc, pctx)
}
-func (s *ccFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
+func (s *ccRustFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
packages := s.Packages.Strings()
sort.Strings(packages)
sort.Strings(s.FuzzPackager.SharedLibInstallStrings)
@@ -460,7 +464,7 @@ func GetSharedLibsToZip(sharedLibraries android.Paths, module LinkableInterface,
// For each architecture-specific shared library dependency, we need to
// install it to the output directory. Setup the install destination here,
// which will be used by $(copy-many-files) in the Make backend.
- installDestination := sharedLibraryInstallLocation(
+ installDestination := SharedLibraryInstallLocation(
library, module.Host(), fuzzDir, archString)
if (*sharedLibraryInstalled)[installDestination] {
continue
@@ -479,7 +483,7 @@ func GetSharedLibsToZip(sharedLibraries android.Paths, module LinkableInterface,
// we want symbolization tools (like `stack`) to be able to find the symbols
// in $ANDROID_PRODUCT_OUT/symbols automagically.
if !module.Host() {
- symbolsInstallDestination := sharedLibrarySymbolsInstallLocation(library, fuzzDir, archString)
+ symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(library, fuzzDir, archString)
symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$")
s.SharedLibInstallStrings = append(s.SharedLibInstallStrings,
library.String()+":"+symbolsInstallDestination)
diff --git a/cc/library.go b/cc/library.go
index b644728b6..61e3a9344 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -243,7 +243,6 @@ type bazelCcLibraryAttributes struct {
Local_includes bazel.StringListAttribute
Absolute_includes bazel.StringListAttribute
Linkopts bazel.StringListAttribute
- Use_libcrt bazel.BoolAttribute
Rtti bazel.BoolAttribute
Stl *string
@@ -251,7 +250,6 @@ type bazelCcLibraryAttributes struct {
C_std *string
// This is shared only.
- Link_crt bazel.BoolAttribute
Additional_linker_inputs bazel.LabelListAttribute
// Common properties shared between both shared and static variants.
@@ -360,7 +358,6 @@ func libraryBp2Build(ctx android.TopDownMutatorContext, m *Module) {
Export_system_includes: exportedIncludes.SystemIncludes,
Local_includes: compilerAttrs.localIncludes,
Absolute_includes: compilerAttrs.absoluteIncludes,
- Use_libcrt: linkerAttrs.useLibcrt,
Rtti: compilerAttrs.rtti,
Stl: compilerAttrs.stl,
Cpp_std: compilerAttrs.cppStd,
@@ -381,8 +378,6 @@ func libraryBp2Build(ctx android.TopDownMutatorContext, m *Module) {
Local_includes: compilerAttrs.localIncludes,
Absolute_includes: compilerAttrs.absoluteIncludes,
Linkopts: linkerAttrs.linkopts,
- Link_crt: linkerAttrs.linkCrt,
- Use_libcrt: linkerAttrs.useLibcrt,
Rtti: compilerAttrs.rtti,
Stl: compilerAttrs.stl,
Cpp_std: compilerAttrs.cppStd,
@@ -845,7 +840,11 @@ func (handler *ccLibraryBazelHandler) generateStaticBazelBuildActions(ctx androi
ctx.ModuleErrorf("expected exactly one root archive file for '%s', but got %s", label, rootStaticArchives)
return
}
- outputFilePath := android.PathForBazelOut(ctx, rootStaticArchives[0])
+ var outputFilePath android.Path = android.PathForBazelOut(ctx, rootStaticArchives[0])
+ if len(ccInfo.TidyFiles) > 0 {
+ handler.module.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles)
+ outputFilePath = android.AttachValidationActions(ctx, outputFilePath, handler.module.tidyFiles)
+ }
handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
objPaths := ccInfo.CcObjectFiles
@@ -881,9 +880,13 @@ func (handler *ccLibraryBazelHandler) generateSharedBazelBuildActions(ctx androi
ctx.ModuleErrorf("expected exactly one root dynamic library file for '%s', but got %s", label, rootDynamicLibraries)
return
}
- outputFilePath := android.PathForBazelOut(ctx, rootDynamicLibraries[0])
- handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
+ var outputFilePath android.Path = android.PathForBazelOut(ctx, rootDynamicLibraries[0])
+ if len(ccInfo.TidyFiles) > 0 {
+ handler.module.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles)
+ outputFilePath = android.AttachValidationActions(ctx, outputFilePath, handler.module.tidyFiles)
+ }
+ handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
handler.module.linker.(*libraryDecorator).unstrippedOutputFile = android.PathForBazelOut(ctx, ccInfo.UnstrippedOutput)
var tocFile android.OptionalPath
@@ -907,12 +910,12 @@ func (handler *ccLibraryBazelHandler) generateSharedBazelBuildActions(ctx androi
func (handler *ccLibraryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
bazelCtx := ctx.Config().BazelContext
- bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKey(ctx))
+ bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
}
func (handler *ccLibraryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
bazelCtx := ctx.Config().BazelContext
- ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKey(ctx))
+ ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
if err != nil {
ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
return
@@ -1492,7 +1495,7 @@ func (library *libraryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.StaticProperties.Static.Export_shared_lib_headers...)
deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.StaticProperties.Static.Export_static_lib_headers...)
} else if library.shared() {
- if !Bool(library.baseLinker.Properties.Nocrt) {
+ if library.baseLinker.Properties.crt() {
deps.CrtBegin = append(deps.CrtBegin, ctx.toolchain().CrtBeginSharedLibrary()...)
deps.CrtEnd = append(deps.CrtEnd, ctx.toolchain().CrtEndSharedLibrary()...)
}
@@ -2876,13 +2879,10 @@ func sharedOrStaticLibraryBp2Build(ctx android.TopDownMutatorContext, module *Mo
commonAttrs.Deps.Add(baseAttributes.protoDependency)
attrs = &bazelCcLibraryStaticAttributes{
staticOrSharedAttributes: commonAttrs,
-
- Use_libcrt: linkerAttrs.useLibcrt,
-
- Rtti: compilerAttrs.rtti,
- Stl: compilerAttrs.stl,
- Cpp_std: compilerAttrs.cppStd,
- C_std: compilerAttrs.cStd,
+ Rtti: compilerAttrs.rtti,
+ Stl: compilerAttrs.stl,
+ Cpp_std: compilerAttrs.cppStd,
+ C_std: compilerAttrs.cStd,
Export_includes: exportedIncludes.Includes,
Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
@@ -2907,8 +2907,6 @@ func sharedOrStaticLibraryBp2Build(ctx android.TopDownMutatorContext, module *Mo
Asflags: asFlags,
Linkopts: linkerAttrs.linkopts,
- Link_crt: linkerAttrs.linkCrt,
- Use_libcrt: linkerAttrs.useLibcrt,
Use_version_lib: linkerAttrs.useVersionLib,
Rtti: compilerAttrs.rtti,
@@ -2966,13 +2964,11 @@ func sharedOrStaticLibraryBp2Build(ctx android.TopDownMutatorContext, module *Mo
type bazelCcLibraryStaticAttributes struct {
staticOrSharedAttributes
- Use_libcrt bazel.BoolAttribute
Use_version_lib bazel.BoolAttribute
-
- Rtti bazel.BoolAttribute
- Stl *string
- Cpp_std *string
- C_std *string
+ Rtti bazel.BoolAttribute
+ Stl *string
+ Cpp_std *string
+ C_std *string
Export_includes bazel.StringListAttribute
Export_absolute_includes bazel.StringListAttribute
@@ -2992,10 +2988,7 @@ type bazelCcLibraryStaticAttributes struct {
type bazelCcLibrarySharedAttributes struct {
staticOrSharedAttributes
- Linkopts bazel.StringListAttribute
- Link_crt bazel.BoolAttribute // Only for linking shared library (and cc_binary)
-
- Use_libcrt bazel.BoolAttribute
+ Linkopts bazel.StringListAttribute
Use_version_lib bazel.BoolAttribute
Rtti bazel.BoolAttribute
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 6440ee235..1dee72679 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -59,12 +59,12 @@ var _ BazelHandler = (*libraryHeaderBazelHandler)(nil)
func (handler *libraryHeaderBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
bazelCtx := ctx.Config().BazelContext
- bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKey(ctx))
+ bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
}
func (h *libraryHeaderBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
bazelCtx := ctx.Config().BazelContext
- ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKey(ctx))
+ ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
if err != nil {
ctx.ModuleErrorf(err.Error())
return
@@ -76,7 +76,11 @@ func (h *libraryHeaderBazelHandler) ProcessBazelQueryResponse(ctx android.Module
return
}
- outputPath := android.PathForBazelOut(ctx, outputPaths[0])
+ var outputPath android.Path = android.PathForBazelOut(ctx, outputPaths[0])
+ if len(ccInfo.TidyFiles) > 0 {
+ h.module.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles)
+ outputPath = android.AttachValidationActions(ctx, outputPath, h.module.tidyFiles)
+ }
h.module.outputFile = android.OptionalPathForPath(outputPath)
// HeaderLibraryInfo is an empty struct to indicate to dependencies that this is a header library
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 1bcbdc55d..e743bb6ce 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -405,7 +405,7 @@ func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, b
}
// Add the collated include dir properties to the output.
- for _, property := range android.SortedStringKeys(includeDirs) {
+ for _, property := range android.SortedKeys(includeDirs) {
outputProperties.AddProperty(property, includeDirs[property])
}
diff --git a/cc/library_test.go b/cc/library_test.go
index dab5bb804..de3db99db 100644
--- a/cc/library_test.go
+++ b/cc/library_test.go
@@ -308,6 +308,75 @@ cc_library {
android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps)
}
+func TestCcLibraryWithBazelValidations(t *testing.T) {
+ t.Parallel()
+ bp := `
+cc_library {
+ name: "foo",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo/bar:bar" },
+ tidy: true,
+}`
+ config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: "outputbase",
+ LabelToCcInfo: map[string]cquery.CcInfo{
+ "//foo/bar:bar": cquery.CcInfo{
+ CcObjectFiles: []string{"foo.o"},
+ Includes: []string{"include"},
+ SystemIncludes: []string{"system_include"},
+ Headers: []string{"foo.h"},
+ RootDynamicLibraries: []string{"foo.so"},
+ UnstrippedOutput: "foo_unstripped.so",
+ },
+ "//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{
+ CcObjectFiles: []string{"foo.o"},
+ Includes: []string{"include"},
+ SystemIncludes: []string{"system_include"},
+ Headers: []string{"foo.h"},
+ RootStaticArchives: []string{"foo.a"},
+ TidyFiles: []string{"foo.c.tidy"},
+ },
+ },
+ }
+ ctx := android.GroupFixturePreparers(
+ prepareForCcTest,
+ android.FixtureMergeEnv(map[string]string{
+ "ALLOW_LOCAL_TIDY_TRUE": "1",
+ }),
+ ).RunTestWithConfig(t, config).TestContext
+
+ staticFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module()
+ outputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+ }
+
+ expectedOutputFiles := []string{"out/soong/.intermediates/foo/android_arm_armv7-a-neon_static/validated/foo.a"}
+ android.AssertPathsRelativeToTopEquals(t, "output files", expectedOutputFiles, outputFiles)
+
+ flagExporter := ctx.ModuleProvider(staticFoo, FlagExporterInfoProvider).(FlagExporterInfo)
+ android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs)
+ android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs)
+ android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders)
+ android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps)
+
+ sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
+ outputFiles, err = sharedFoo.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_library outputfiles %s", err)
+ }
+ expectedOutputFiles = []string{"outputbase/execroot/__main__/foo.so"}
+ android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
+
+ android.AssertStringEquals(t, "unstripped shared library", "outputbase/execroot/__main__/foo_unstripped.so", sharedFoo.(*Module).linker.unstrippedOutputFilePath().String())
+ flagExporter = ctx.ModuleProvider(sharedFoo, FlagExporterInfoProvider).(FlagExporterInfo)
+ android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs)
+ android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs)
+ android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders)
+ android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps)
+}
+
func TestLibraryVersionScript(t *testing.T) {
t.Parallel()
result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, `
@@ -344,6 +413,59 @@ func TestLibraryDynamicList(t *testing.T) {
}
+func TestCcLibrarySharedWithBazelValidations(t *testing.T) {
+ t.Parallel()
+ bp := `
+cc_library_shared {
+ name: "foo",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo/bar:bar" },
+ tidy: true,
+}`
+ config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: "outputbase",
+ LabelToCcInfo: map[string]cquery.CcInfo{
+ "//foo/bar:bar": cquery.CcInfo{
+ CcObjectFiles: []string{"foo.o"},
+ Includes: []string{"include"},
+ SystemIncludes: []string{"system_include"},
+ RootDynamicLibraries: []string{"foo.so"},
+ TocFile: "foo.so.toc",
+ TidyFiles: []string{"foo.c.tidy"},
+ },
+ },
+ }
+ ctx := android.GroupFixturePreparers(
+ prepareForCcTest,
+ android.FixtureMergeEnv(map[string]string{
+ "ALLOW_LOCAL_TIDY_TRUE": "1",
+ }),
+ ).RunTestWithConfig(t, config).TestContext
+
+ sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
+ producer := sharedFoo.(android.OutputFileProducer)
+ outputFiles, err := producer.OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+ }
+ expectedOutputFiles := []string{"out/soong/.intermediates/foo/android_arm_armv7-a-neon_shared/validated/foo.so"}
+ android.AssertPathsRelativeToTopEquals(t, "output files", expectedOutputFiles, outputFiles)
+
+ tocFilePath := sharedFoo.(*Module).Toc()
+ if !tocFilePath.Valid() {
+ t.Errorf("Invalid tocFilePath: %s", tocFilePath)
+ }
+ tocFile := tocFilePath.Path()
+ expectedToc := "outputbase/execroot/__main__/foo.so.toc"
+ android.AssertStringEquals(t, "toc file", expectedToc, tocFile.String())
+
+ entries := android.AndroidMkEntriesForTest(t, ctx, sharedFoo)[0]
+ expectedFlags := []string{"-Ioutputbase/execroot/__main__/include", "-isystem outputbase/execroot/__main__/system_include"}
+ gotFlags := entries.EntryMap["LOCAL_EXPORT_CFLAGS"]
+ android.AssertDeepEquals(t, "androidmk exported cflags", expectedFlags, gotFlags)
+}
+
func TestCcLibrarySharedWithBazel(t *testing.T) {
t.Parallel()
bp := `
diff --git a/cc/linkable.go b/cc/linkable.go
index 0522fc6fc..9578807f8 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -3,6 +3,7 @@ package cc
import (
"android/soong/android"
"android/soong/bazel/cquery"
+ "android/soong/fuzz"
"android/soong/snapshot"
"github.com/google/blueprint"
@@ -120,6 +121,17 @@ type LinkableInterface interface {
IsPrebuilt() bool
Toc() android.OptionalPath
+ // IsFuzzModule returns true if this a *_fuzz module.
+ IsFuzzModule() bool
+
+ // FuzzPackagedModule returns the fuzz.FuzzPackagedModule for this module.
+ // Expects that IsFuzzModule returns true.
+ FuzzPackagedModule() fuzz.FuzzPackagedModule
+
+ // FuzzSharedLibraries returns the shared library dependencies for this module.
+ // Expects that IsFuzzModule returns true.
+ FuzzSharedLibraries() android.Paths
+
Device() bool
Host() bool
@@ -256,6 +268,9 @@ type LinkableInterface interface {
// Partition returns the partition string for this module.
Partition() string
+
+ // FuzzModule returns the fuzz.FuzzModule associated with the module.
+ FuzzModuleStruct() fuzz.FuzzModule
}
var (
diff --git a/cc/linker.go b/cc/linker.go
index 371d78daf..e49b97d0b 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -237,29 +237,14 @@ type BaseLinkerProperties struct {
Exclude_shared_libs []string `android:"arch_variant"`
}
-func invertBoolPtr(value *bool) *bool {
- if value == nil {
- return nil
- }
- ret := !(*value)
- return &ret
-}
-
-func (blp *BaseLinkerProperties) crt() *bool {
- val := invertBoolPtr(blp.Nocrt)
- if val != nil && *val {
- // == True
- //
- // Since crt is enabled for almost every module compiling against the Bionic runtime,
- // use `nil` when it's enabled, and rely on the Starlark macro to set it to True by default.
- // This keeps the BUILD files clean.
- return nil
- }
- return val // can be False or nil
+func (blp *BaseLinkerProperties) crt() bool {
+ // Since crt is enabled for almost every module compiling against the Bionic runtime,
+ // we interpret `nil` as enabled.
+ return blp.Nocrt == nil || !*blp.Nocrt
}
-func (blp *BaseLinkerProperties) libCrt() *bool {
- return invertBoolPtr(blp.No_libcrt)
+func (blp *BaseLinkerProperties) libCrt() bool {
+ return blp.No_libcrt == nil || !*blp.No_libcrt
}
func NewBaseLinker(sanitize *sanitize) *baseLinker {
@@ -392,7 +377,7 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
if ctx.toolchain().Bionic() {
// libclang_rt.builtins has to be last on the command line
- if !Bool(linker.Properties.No_libcrt) && !ctx.header() {
+ if linker.Properties.libCrt() && !ctx.header() {
deps.UnexportedStaticLibs = append(deps.UnexportedStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
}
@@ -415,7 +400,7 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
ctx.PropertyErrorf("system_shared_libs", "libdl must be after libc")
}
} else if ctx.toolchain().Musl() {
- if !Bool(linker.Properties.No_libcrt) && !ctx.header() {
+ if linker.Properties.libCrt() && !ctx.header() {
deps.UnexportedStaticLibs = append(deps.UnexportedStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
}
}
diff --git a/cc/lto_test.go b/cc/lto_test.go
index fbd91be46..4220f3255 100644
--- a/cc/lto_test.go
+++ b/cc/lto_test.go
@@ -15,10 +15,11 @@
package cc
import (
- "android/soong/android"
"strings"
"testing"
+ "android/soong/android"
+
"github.com/google/blueprint"
)
@@ -177,3 +178,64 @@ func TestThinLtoOnlyOnStaticDep(t *testing.T) {
t.Errorf("'baz' expected to have flags %q, but got %q", w, libFooCFlags)
}
}
+
+func TestLtoDisabledButEnabledForArch(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library {
+ name: "libfoo",
+ srcs: ["foo.c"],
+ lto: {
+ never: true,
+ },
+ target: {
+ android_arm: {
+ lto: {
+ never: false,
+ thin: true,
+ },
+ },
+ },
+ }`
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ ).RunTestWithBp(t, bp)
+
+ libFooWithLto := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
+ libFooWithoutLto := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld")
+
+ android.AssertStringDoesContain(t, "missing flag for LTO in variant that expects it",
+ libFooWithLto.Args["ldFlags"], "-flto=thin")
+ android.AssertStringDoesNotContain(t, "got flag for LTO in variant that doesn't expect it",
+ libFooWithoutLto.Args["ldFlags"], "-flto=thin")
+}
+
+func TestLtoDoesNotPropagateToRuntimeLibs(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library {
+ name: "runtime_libbar",
+ srcs: ["bar.c"],
+ }
+
+ cc_library {
+ name: "libfoo",
+ srcs: ["foo.c"],
+ runtime_libs: ["runtime_libbar"],
+ lto: {
+ thin: true,
+ },
+ }`
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ ).RunTestWithBp(t, bp)
+
+ libFoo := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
+ libBar := result.ModuleForTests("runtime_libbar", "android_arm_armv7-a-neon_shared").Rule("ld")
+
+ android.AssertStringDoesContain(t, "missing flag for LTO in LTO enabled library",
+ libFoo.Args["ldFlags"], "-flto=thin")
+ android.AssertStringDoesNotContain(t, "got flag for LTO in runtime_lib",
+ libBar.Args["ldFlags"], "-flto=thin")
+}
diff --git a/cc/ndk_api_coverage_parser/OWNERS b/cc/ndk_api_coverage_parser/OWNERS
deleted file mode 100644
index a90c48c15..000000000
--- a/cc/ndk_api_coverage_parser/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-sophiez@google.com
diff --git a/cc/object.go b/cc/object.go
index 11ce7939c..ef4446746 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -54,12 +54,12 @@ var _ BazelHandler = (*objectBazelHandler)(nil)
func (handler *objectBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
bazelCtx := ctx.Config().BazelContext
- bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKey(ctx))
+ bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
}
func (handler *objectBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
bazelCtx := ctx.Config().BazelContext
- objPaths, err := bazelCtx.GetOutputFiles(label, android.GetConfigKey(ctx))
+ objPaths, err := bazelCtx.GetOutputFiles(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
if err != nil {
ctx.ModuleErrorf(err.Error())
return
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 9e62bf8ba..bb517eadb 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -488,13 +488,17 @@ func (h *prebuiltLibraryBazelHandler) processStaticBazelQueryResponse(ctx androi
return true
}
- out := android.PathForBazelOut(ctx, staticLibs[0])
- h.module.outputFile = android.OptionalPathForPath(out)
+ var outputPath android.Path = android.PathForBazelOut(ctx, staticLibs[0])
+ if len(ccInfo.TidyFiles) > 0 {
+ h.module.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles)
+ outputPath = android.AttachValidationActions(ctx, outputPath, h.module.tidyFiles)
+ }
- depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(out).Build()
- ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
- StaticLibrary: out,
+ h.module.outputFile = android.OptionalPathForPath(outputPath)
+ depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(outputPath).Build()
+ ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+ StaticLibrary: outputPath,
TransitiveStaticLibrariesForOrdering: depSet,
})
@@ -518,21 +522,26 @@ func (h *prebuiltLibraryBazelHandler) processSharedBazelQueryResponse(ctx androi
return true
}
- out := android.PathForBazelOut(ctx, sharedLibs[0])
- h.module.outputFile = android.OptionalPathForPath(out)
+ var outputPath android.Path = android.PathForBazelOut(ctx, sharedLibs[0])
+ if len(ccInfo.TidyFiles) > 0 {
+ h.module.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles)
+ outputPath = android.AttachValidationActions(ctx, outputPath, h.module.tidyFiles)
+ }
+
+ h.module.outputFile = android.OptionalPathForPath(outputPath)
// FIXME(b/214600441): We don't yet strip prebuilt shared libraries
- h.library.unstrippedOutputFile = out
+ h.library.unstrippedOutputFile = outputPath
var toc android.Path
if len(ccInfo.TocFile) > 0 {
toc = android.PathForBazelOut(ctx, ccInfo.TocFile)
} else {
- toc = out // Just reuse `out` so ninja still gets an input but won't matter
+ toc = outputPath // Just reuse `out` so ninja still gets an input but won't matter
}
info := SharedLibraryInfo{
- SharedLibrary: out,
+ SharedLibrary: outputPath,
TableOfContents: android.OptionalPathForPath(toc),
Target: ctx.Target(),
}
@@ -752,12 +761,12 @@ var _ BazelHandler = (*prebuiltBinaryBazelHandler)(nil)
func (h *prebuiltBinaryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
bazelCtx := ctx.Config().BazelContext
- bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKey(ctx))
+ bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
}
func (h *prebuiltBinaryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
bazelCtx := ctx.Config().BazelContext
- outputs, err := bazelCtx.GetOutputFiles(label, android.GetConfigKey(ctx))
+ outputs, err := bazelCtx.GetOutputFiles(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
if err != nil {
ctx.ModuleErrorf(err.Error())
return
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 95fa99e43..405680c39 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -443,6 +443,75 @@ cc_prebuilt_library {
expectedStaticOutputFiles, staticOutputFiles.Strings())
}
+func TestPrebuiltLibraryWithBazelValidations(t *testing.T) {
+ const bp = `
+cc_prebuilt_library {
+ name: "foo",
+ shared: {
+ srcs: ["foo.so"],
+ },
+ static: {
+ srcs: ["foo.a"],
+ },
+ bazel_module: { label: "//foo/bar:bar" },
+ tidy: true,
+}`
+ outBaseDir := "outputbase"
+ result := android.GroupFixturePreparers(
+ prepareForPrebuiltTest,
+ android.FixtureMergeEnv(map[string]string{
+ "ALLOW_LOCAL_TIDY_TRUE": "1",
+ }),
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: outBaseDir,
+ LabelToCcInfo: map[string]cquery.CcInfo{
+ "//foo/bar:bar": cquery.CcInfo{
+ CcSharedLibraryFiles: []string{"foo.so"},
+ TidyFiles: []string{"foo.c.tidy"},
+ },
+ "//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{
+ CcStaticLibraryFiles: []string{"foo.a"},
+ TidyFiles: []string{"foo.c.tidy"},
+ },
+ },
+ }
+ }),
+ ).RunTestWithBp(t, bp)
+ sharedFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
+
+ expectedOutputFile := "out/soong/.intermediates/foo/android_arm_armv7-a-neon_shared/validated/foo.so"
+ sharedInfo := result.ModuleProvider(sharedFoo, SharedLibraryInfoProvider).(SharedLibraryInfo)
+ android.AssertPathRelativeToTopEquals(t,
+ "prebuilt library shared target path did not exist or did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.",
+ expectedOutputFile, sharedInfo.SharedLibrary)
+
+ outputFiles, err := sharedFoo.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+ }
+ expectedOutputFiles := []string{expectedOutputFile}
+ android.AssertPathsRelativeToTopEquals(t,
+ "prebuilt library shared target output files did not match expected.",
+ expectedOutputFiles, outputFiles)
+
+ staticFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module()
+ staticInfo := result.ModuleProvider(staticFoo, StaticLibraryInfoProvider).(StaticLibraryInfo)
+ expectedStaticOutputFile := "out/soong/.intermediates/foo/android_arm_armv7-a-neon_static/validated/foo.a"
+ android.AssertPathRelativeToTopEquals(t,
+ "prebuilt library static target path did not exist or did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.",
+ expectedStaticOutputFile, staticInfo.StaticLibrary)
+
+ staticOutputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_object staticOutputFiles %s", err)
+ }
+ expectedStaticOutputFiles := []string{expectedStaticOutputFile}
+ android.AssertPathsRelativeToTopEquals(t,
+ "prebuilt library static target output files did not match expected.",
+ expectedStaticOutputFiles, staticOutputFiles)
+}
+
func TestPrebuiltLibraryWithBazelStaticDisabled(t *testing.T) {
const bp = `
cc_prebuilt_library {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 66f459abe..aa61453ce 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -1716,9 +1716,9 @@ func (s *sanitizerStaticLibsMap) add(c LinkableInterface, name string) {
// These are to be used by use_soong_sanitized_static_libraries.
// See build/make/core/binary.mk for more details.
func (s *sanitizerStaticLibsMap) exportToMake(ctx android.MakeVarsContext) {
- for _, image := range android.SortedStringKeys(s.libsMap) {
+ for _, image := range android.SortedKeys(s.libsMap) {
archMap := s.libsMap[ImageVariantType(image)]
- for _, arch := range android.SortedStringKeys(archMap) {
+ for _, arch := range android.SortedKeys(archMap) {
libs := archMap[arch]
sort.Strings(libs)
diff --git a/cc/sdk.go b/cc/sdk.go
index 3e50c9f4b..23dd0cb2d 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -47,16 +47,16 @@ func sdkMutator(ctx android.BottomUpMutatorContext) {
// Mark the SDK variant.
modules[1].(*Module).Properties.IsSdkVariant = true
+ // SDK variant is not supposed to be installed
+ modules[1].(*Module).Properties.PreventInstall = true
if ctx.Config().UnbundledBuildApps() {
// For an unbundled apps build, hide the platform variant from Make.
modules[0].(*Module).Properties.HideFromMake = true
- modules[0].(*Module).Properties.PreventInstall = true
} else {
// For a platform build, mark the SDK variant so that it gets a ".sdk" suffix when
// exposed to Make.
modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
- modules[1].(*Module).Properties.PreventInstall = true
}
ctx.AliasVariation("")
} else if isCcModule && ccModule.isImportedApiLibrary() {
@@ -64,16 +64,19 @@ func sdkMutator(ctx android.BottomUpMutatorContext) {
if apiLibrary.hasNDKStubs() && ccModule.canUseSdk() {
// Handle cc_api_library module with NDK stubs and variants only which can use SDK
modules := ctx.CreateVariations("", "sdk")
+
+ // Mark the SDK variant.
modules[1].(*Module).Properties.IsSdkVariant = true
+ // SDK variant is not supposed to be installed
+ modules[1].(*Module).Properties.PreventInstall = true
+
if ctx.Config().UnbundledBuildApps() {
// For an unbundled apps build, hide the platform variant from Make.
modules[0].(*Module).Properties.HideFromMake = true
- modules[0].(*Module).Properties.PreventInstall = true
} else {
// For a platform build, mark the SDK variant so that it gets a ".sdk" suffix when
// exposed to Make.
modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
- modules[1].(*Module).Properties.PreventInstall = true
}
} else {
ccModule.Properties.Sdk_version = nil
diff --git a/cc/sdk_test.go b/cc/sdk_test.go
index 61925e30c..790440cb9 100644
--- a/cc/sdk_test.go
+++ b/cc/sdk_test.go
@@ -101,3 +101,95 @@ func TestSdkMutator(t *testing.T) {
assertDep(t, libsdkNDK, libcxxNDK)
assertDep(t, libsdkPlatform, libcxxPlatform)
}
+
+func TestMakeModuleNameForSdkVariant(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libfoo",
+ srcs: ["main_test.cpp"],
+ sdk_version: "current",
+ stl: "none",
+ }
+ `
+ platformVariant := "android_arm64_armv8-a_shared"
+ sdkVariant := "android_arm64_armv8-a_sdk_shared"
+ testCases := []struct {
+ name string
+ unbundledApps []string
+ variant string
+ skipInstall bool // soong skips install
+ hideFromMake bool // no make entry
+ makeUninstallable bool // make skips install
+ makeModuleName string
+ }{
+ {
+ name: "platform variant in normal builds",
+ unbundledApps: nil,
+ variant: platformVariant,
+ // installable in soong
+ skipInstall: false,
+ // visiable in Make as "libfoo"
+ hideFromMake: false,
+ makeModuleName: "libfoo",
+ // installable in Make
+ makeUninstallable: false,
+ },
+ {
+ name: "sdk variant in normal builds",
+ unbundledApps: nil,
+ variant: sdkVariant,
+ // soong doesn't install
+ skipInstall: true,
+ // visible in Make as "libfoo.sdk"
+ hideFromMake: false,
+ makeModuleName: "libfoo.sdk",
+ // but not installed
+ makeUninstallable: true,
+ },
+ {
+ name: "platform variant in unbunded builds",
+ unbundledApps: []string{"bar"},
+ variant: platformVariant,
+ // installable in soong
+ skipInstall: false,
+ // hidden from make
+ hideFromMake: true,
+ },
+ {
+ name: "sdk variant in unbunded builds",
+ unbundledApps: []string{"bar"},
+ variant: sdkVariant,
+ // soong doesn't install
+ skipInstall: true,
+ // visible in Make as "libfoo"
+ hideFromMake: false,
+ makeModuleName: "libfoo",
+ // but not installed
+ makeUninstallable: true,
+ },
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ fixture := android.GroupFixturePreparers(prepareForCcTest,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Unbundled_build_apps = tc.unbundledApps
+ }),
+ )
+ ctx := fixture.RunTestWithBp(t, bp).TestContext
+ module := ctx.ModuleForTests("libfoo", tc.variant).Module().(*Module)
+ android.AssertBoolEquals(t, "IsSkipInstall", tc.skipInstall, module.IsSkipInstall())
+ android.AssertBoolEquals(t, "HideFromMake", tc.hideFromMake, module.HiddenFromMake())
+ if !tc.hideFromMake {
+ entries := android.AndroidMkEntriesForTest(t, ctx, module)[0]
+ android.AssertStringEquals(t, "LOCAL_MODULE",
+ tc.makeModuleName, entries.EntryMap["LOCAL_MODULE"][0])
+ actualUninstallable := false
+ if actual, ok := entries.EntryMap["LOCAL_UNINSTALLABLE_MODULE"]; ok {
+ actualUninstallable = "true" == actual[0]
+ }
+ android.AssertBoolEquals(t, "LOCAL_UNINSTALLABLE_MODULE",
+ tc.makeUninstallable, actualUninstallable)
+ }
+ })
+ }
+}
diff --git a/cc/stub_library.go b/cc/stub_library.go
index 76da782ee..f324dcc9b 100644
--- a/cc/stub_library.go
+++ b/cc/stub_library.go
@@ -73,7 +73,7 @@ func stubLibrariesSingleton() android.Singleton {
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), " "))
+ ctx.Strict("STUB_LIBRARIES", strings.Join(android.SortedKeys(s.stubLibraryMap), " "))
// Export the list of API XML files to Make.
sort.Strings(s.apiListCoverageXmlPaths)
diff --git a/cc/test.go b/cc/test.go
index 5c4d54833..27de06b07 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -649,7 +649,11 @@ func (handler *ccTestBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleC
return
}
- outputFilePath := android.PathForBazelOut(ctx, info.OutputFile)
+ var outputFilePath android.Path = android.PathForBazelOut(ctx, info.OutputFile)
+ if len(info.TidyFiles) > 0 {
+ handler.module.tidyFiles = android.PathsForBazelOut(ctx, info.TidyFiles)
+ outputFilePath = android.AttachValidationActions(ctx, outputFilePath, handler.module.tidyFiles)
+ }
handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
handler.module.linker.(*testBinary).unstrippedOutputFile = android.PathForBazelOut(ctx, info.UnstrippedOutput)
diff --git a/cc/util.go b/cc/util.go
index 4e1003739..aa0f6b5d6 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -118,7 +118,7 @@ func combineNoticesRule(ctx android.SingletonContext, paths android.Paths, out s
// ...
func installMapListFileRule(ctx android.SingletonContext, m map[string]string, path string) android.OutputPath {
var txtBuilder strings.Builder
- for idx, k := range android.SortedStringKeys(m) {
+ for idx, k := range android.SortedKeys(m) {
if idx > 0 {
txtBuilder.WriteString("\n")
}
diff --git a/cc/vndk.go b/cc/vndk.go
index 6ab473425..3b7c87dea 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -876,7 +876,7 @@ func (c *vndkSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
})
ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES",
- strings.Join(android.SortedStringKeys(movedToApexLlndkLibraries), " "))
+ strings.Join(android.SortedKeys(movedToApexLlndkLibraries), " "))
ctx.Strict("VNDK_LIBRARIES_FILE", c.vndkLibrariesFile.String())
ctx.Strict("SOONG_VNDK_SNAPSHOT_ZIP", c.vndkSnapshotZipFile.String())
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 0115f4acc..0212075e0 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -515,7 +515,8 @@ func runSoongUiForProduct(mpctx *mpContext, product string) {
"TARGET_BUILD_VARIANT="+*buildVariant,
"TARGET_BUILD_TYPE=release",
"TARGET_BUILD_APPS=",
- "TARGET_BUILD_UNBUNDLED=")
+ "TARGET_BUILD_UNBUNDLED=",
+ "USE_RBE=false") // Disabling RBE saves ~10 secs per product
if *alternateResultDir {
cmd.Env = append(cmd.Env,
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 29a6f9552..5c187f6cf 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -81,6 +81,7 @@ func init() {
flag.BoolVar(&cmdlineArgs.BazelMode, "bazel-mode", false, "use bazel for analysis of certain modules")
flag.BoolVar(&cmdlineArgs.BazelModeStaging, "bazel-mode-staging", false, "use bazel for analysis of certain near-ready modules")
flag.BoolVar(&cmdlineArgs.BazelModeDev, "bazel-mode-dev", false, "use bazel for analysis of a large number of modules (less stable)")
+ flag.BoolVar(&cmdlineArgs.UseBazelProxy, "use-bazel-proxy", false, "communicate with bazel using unix socket proxy instead of spawning subprocesses")
// Flags that probably shouldn't be flags of soong_build, but we haven't found
// the time to remove them yet
@@ -178,7 +179,8 @@ func runApiBp2build(ctx *android.Context, extraNinjaDeps []string) string {
ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
// Create soong_injection repository
- soongInjectionFiles := bp2build.CreateSoongInjectionDirFiles(codegenContext, bp2build.CreateCodegenMetrics())
+ soongInjectionFiles, err := bp2build.CreateSoongInjectionDirFiles(codegenContext, bp2build.CreateCodegenMetrics())
+ maybeQuit(err, "")
absoluteSoongInjectionDir := shared.JoinPath(topDir, ctx.Config().SoongOutDir(), bazel.SoongInjectionDirName)
for _, file := range soongInjectionFiles {
// The API targets in api_bp2build workspace do not have any dependency on api_bp2build.
@@ -447,6 +449,7 @@ func bazelArtifacts() []string {
"bazel-genfiles",
"bazel-out",
"bazel-testlogs",
+ "bazel-workspace",
"bazel-" + filepath.Base(topDir),
}
}
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 661bd5d2e..fd718c29f 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -218,12 +218,12 @@ func main() {
trace.SetOutput(filepath.Join(logsDir, c.logsPrefix+"build.trace"))
- c.run(buildCtx, config, args)
-
- defer met.Dump(soongMetricsFile)
if !config.SkipMetricsUpload() {
defer build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, bazelProfileFile, bazelMetricsFile, metricsFiles...)
}
+ defer met.Dump(soongMetricsFile)
+
+ c.run(buildCtx, config, args)
}
diff --git a/compliance/OWNERS b/compliance/OWNERS
new file mode 100644
index 000000000..f52e201c1
--- /dev/null
+++ b/compliance/OWNERS
@@ -0,0 +1,8 @@
+# OSEP Build
+bbadour@google.com
+kanouche@google.com
+napier@google.com
+
+# Open Source Compliance Tools
+rtp@google.com
+austinyuan@google.com
diff --git a/dexpreopt/OWNERS b/dexpreopt/OWNERS
deleted file mode 100644
index 5a2a1983f..000000000
--- a/dexpreopt/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-per-file * = ngeoffray@google.com,calin@google.com,skvadrik@google.com
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index e3404a541..a590c72a5 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -101,6 +101,10 @@ func GenerateDexpreoptRule(ctx android.BuilderContext, globalSoong *GlobalSoongC
}
func dexpreoptDisabled(ctx android.PathContext, global *GlobalConfig, module *ModuleConfig) bool {
+ if ctx.Config().UnbundledBuild() {
+ return true
+ }
+
if contains(global.DisablePreoptModules, module.Name) {
return true
}
diff --git a/docs/OWNERS b/docs/OWNERS
deleted file mode 100644
index 2d7127147..000000000
--- a/docs/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-per-file map_files.md = danalbert@google.com, enh@google.com, jiyong@google.com
-per-file native_code_coverage.md = pirama@google.com, srhines@google.com, allenhair@google.com
-per-file tidy.md = chh@google.com, srhines@google.com
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index 444ffd0aa..a65d9dd5f 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -188,3 +188,40 @@ func TestAvbAddHashFooter(t *testing.T) {
android.AssertStringDoesContain(t, "Can't find --include_descriptors_from_image",
cmd, "--include_descriptors_from_image ")
}
+
+func TestFileSystemShouldInstallCoreVariantIfTargetBuildAppsIsSet(t *testing.T) {
+ context := android.GroupFixturePreparers(
+ fixture,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Unbundled_build_apps = []string{"bar"}
+ }),
+ )
+ result := context.RunTestWithBp(t, `
+ android_system_image {
+ name: "myfilesystem",
+ deps: [
+ "libfoo",
+ ],
+ linker_config_src: "linker.config.json",
+ }
+
+ cc_library {
+ name: "libfoo",
+ shared_libs: [
+ "libbar",
+ ],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "libbar",
+ sdk_version: "9",
+ stl: "none",
+ }
+ `)
+
+ inputs := result.ModuleForTests("myfilesystem", "android_common").Output("deps.zip").Implicits
+ android.AssertStringListContains(t, "filesystem should have libbar even for unbundled build",
+ inputs.Strings(),
+ "out/soong/.intermediates/libbar/android_arm64_armv8-a_shared/libbar.so")
+}
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index 5e5769bf1..8175a3742 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -69,42 +69,222 @@ type ArchOs struct {
Dir string
}
-type PrivilegedLevel string
+type Vector string
const (
- // Environment with the most minimal permissions.
- Constrained PrivilegedLevel = "Constrained"
- // Typical execution environment running unprivileged code.
- Unprivileged = "Unprivileged"
- // May have access to elevated permissions.
- Privileged = "Privileged"
- // Trusted computing base.
- Tcb = "TCB"
- // Bootloader chain.
- Bootloader = "Bootloader"
- // Tusted execution environment.
- Tee = "Tee"
- // Secure enclave.
- Se = "Se"
- // Other.
- Other = "Other"
+ unknown_access_vector Vector = "unknown_access_vector"
+ // The code being fuzzed is reachable from a remote source, or using data
+ // provided by a remote source. For example: media codecs process media files
+ // from the internet, SMS processing handles remote message data.
+ // See
+ // https://source.android.com/docs/security/overview/updates-resources#local-vs-remote
+ // for an explanation of what's considered "remote."
+ remote = "remote"
+ // The code being fuzzed can only be reached locally, such as from an
+ // installed app. As an example, if it's fuzzing a Binder interface, it's
+ // assumed that you'd need a local app to make arbitrary Binder calls.
+ // And the app that's calling the fuzzed code does not require any privileges;
+ // any 3rd party app could make these calls.
+ local_no_privileges_required = "local_no_privileges_required"
+ // The code being fuzzed can only be called locally, and the calling process
+ // requires additional permissions that prevent arbitrary 3rd party apps from
+ // calling the code. For instance: this requires a privileged or signature
+ // permission to reach, or SELinux restrictions prevent the untrusted_app
+ // domain from calling it.
+ local_privileges_required = "local_privileges_required"
+ // The code is only callable on a PC host, not on a production Android device.
+ // For instance, this is fuzzing code used during the build process, or
+ // tooling that does not exist on a user's actual Android device.
+ host_access = "host_access"
+ // The code being fuzzed is only reachable if the user has enabled Developer
+ // Options, or has enabled a persistent Developer Options setting.
+ local_with_developer_options = "local_with_developer_options"
)
+func (vector Vector) isValidVector() bool {
+ switch vector {
+ case "",
+ unknown_access_vector,
+ remote,
+ local_no_privileges_required,
+ local_privileges_required,
+ host_access,
+ local_with_developer_options:
+ return true
+ }
+ return false
+}
+
+type ServicePrivilege string
+
+const (
+ unknown_service_privilege ServicePrivilege = "unknown_service_privilege"
+ // The code being fuzzed runs on a Secure Element. This has access to some
+ // of the most privileged data on the device, such as authentication keys.
+ // Not all devices have a Secure Element.
+ secure_element = "secure_element"
+ // The code being fuzzed runs in the TEE. The TEE is designed to be resistant
+ // to a compromised kernel, and stores sensitive data.
+ trusted_execution = "trusted_execution"
+ // The code being fuzzed has privileges beyond what arbitrary 3rd party apps
+ // have. For instance, it's running as the System UID, or it's in an SELinux
+ // domain that's able to perform calls that can't be made by 3rd party apps.
+ privileged = "privileged"
+ // The code being fuzzed is equivalent to a 3rd party app. It runs in the
+ // untrusted_app SELinux domain, or it only has privileges that are equivalent
+ // to what a 3rd party app could have.
+ unprivileged = "unprivileged"
+ // The code being fuzzed is significantly constrained, and even if it's
+ // compromised, it has significant restrictions that prevent it from
+ // performing most actions. This is significantly more restricted than
+ // UNPRIVILEGED. An example is the isolatedProcess=true setting in a 3rd
+ // party app. Or a process that's very restricted by SELinux, such as
+ // anything in the mediacodec SELinux domain.
+ constrained = "constrained"
+ // The code being fuzzed always has Negligible Security Impact. Even
+ // arbitrary out of bounds writes and full code execution would not be
+ // considered a security vulnerability. This typically only makes sense if
+ // FuzzedCodeUsage is set to FUTURE_VERSION or EXPERIMENTAL, and if
+ // AutomaticallyRouteTo is set to ALWAYS_NSI.
+ nsi = "nsi"
+ // The code being fuzzed only runs on a PC host, not on a production Android
+ // device. For instance, the fuzzer is fuzzing code used during the build
+ // process, or tooling that does not exist on a user's actual Android device.
+ host_only = "host_only"
+)
+
+func (service_privilege ServicePrivilege) isValidServicePrivilege() bool {
+ switch service_privilege {
+ case "",
+ unknown_service_privilege,
+ secure_element,
+ trusted_execution,
+ privileged,
+ unprivileged,
+ constrained,
+ nsi,
+ host_only:
+ return true
+ }
+ return false
+}
+
+type UserData string
+
+const (
+ unknown_user_data UserData = "unknown_user_data"
+ // The process being fuzzed only handles data from a single user, or from a
+ // single process or app. It's possible the process shuts down before
+ // handling data from another user/process/app, or it's possible the process
+ // only ever handles one user's/process's/app's data. As an example, some
+ // print spooler processes are started for a single document and terminate
+ // when done, so each instance only handles data from a single user/app.
+ single_user = "single_user"
+ // The process handles data from multiple users, or from multiple other apps
+ // or processes. Media processes, for instance, can handle media requests
+ // from multiple different apps without restarting. Wi-Fi and network
+ // processes handle data from multiple users, and processes, and apps.
+ multi_user = "multi_user"
+)
+
+func (user_data UserData) isValidUserData() bool {
+ switch user_data {
+ case "",
+ unknown_user_data,
+ single_user,
+ multi_user:
+ return true
+ }
+ return false
+}
+
+type FuzzedCodeUsage string
+
+const (
+ undefined FuzzedCodeUsage = "undefined"
+ unknown = "unknown"
+ // The code being fuzzed exists in a shipped version of Android and runs on
+ // devices in production.
+ shipped = "shipped"
+ // The code being fuzzed is not yet in a shipping version of Android, but it
+ // will be at some point in the future.
+ future_version = "future_version"
+ // The code being fuzzed is not in a shipping version of Android, and there
+ // are no plans to ship it in the future.
+ experimental = "experimental"
+)
+
+func (fuzzed_code_usage FuzzedCodeUsage) isValidFuzzedCodeUsage() bool {
+ switch fuzzed_code_usage {
+ case "",
+ undefined,
+ unknown,
+ shipped,
+ future_version,
+ experimental:
+ return true
+ }
+ return false
+}
+
+type AutomaticallyRouteTo string
+
+const (
+ undefined_routing AutomaticallyRouteTo = "undefined_routing"
+ // Automatically route this to the Android Automotive security team for
+ // assessment.
+ android_automotive = "android_automotive"
+ // This should not be used in fuzzer configurations. It is used internally
+ // by Severity Assigner to flag memory leak reports.
+ memory_leak = "memory_leak"
+ // Route this vulnerability to our Ittiam vendor team for assessment.
+ ittiam = "ittiam"
+ // Reports from this fuzzer are always NSI (see the NSI ServicePrivilegeEnum
+ // value for additional context). It is not possible for this code to ever
+ // have a security vulnerability.
+ always_nsi = "always_nsi"
+ // Route this vulnerability to AIDL team for assessment.
+ aidl = "aidl"
+)
+
+func (automatically_route_to AutomaticallyRouteTo) isValidAutomaticallyRouteTo() bool {
+ switch automatically_route_to {
+ case "",
+ undefined_routing,
+ android_automotive,
+ memory_leak,
+ ittiam,
+ always_nsi,
+ aidl:
+ return true
+ }
+ return false
+}
+
func IsValidConfig(fuzzModule FuzzPackagedModule, moduleName string) bool {
var config = fuzzModule.FuzzProperties.Fuzz_config
if config != nil {
- var level = PrivilegedLevel(config.Privilege_level)
- if level != "" {
- switch level {
- case Constrained, Unprivileged, Privileged, Tcb, Bootloader, Tee, Se, Other:
- return true
- }
- panic(fmt.Errorf("Invalid privileged level in fuzz config in %s", moduleName))
+ if !config.Vector.isValidVector() {
+ panic(fmt.Errorf("Invalid vector in fuzz config in %s", moduleName))
+ }
+
+ if !config.Service_privilege.isValidServicePrivilege() {
+ panic(fmt.Errorf("Invalid service_privilege in fuzz config in %s", moduleName))
+ }
+
+ if !config.Users.isValidUserData() {
+ panic(fmt.Errorf("Invalid users (user_data) in fuzz config in %s", moduleName))
+ }
+
+ if !config.Fuzzed_code_usage.isValidFuzzedCodeUsage() {
+ panic(fmt.Errorf("Invalid fuzzed_code_usage in fuzz config in %s", moduleName))
+ }
+
+ if !config.Automatically_route_to.isValidAutomaticallyRouteTo() {
+ panic(fmt.Errorf("Invalid automatically_route_to in fuzz config in %s", moduleName))
}
- return true
- } else {
- return false
}
+ return true
}
type FuzzConfig struct {
@@ -112,19 +292,24 @@ type FuzzConfig struct {
Cc []string `json:"cc,omitempty"`
// A brief description of what the fuzzed code does.
Description string `json:"description,omitempty"`
- // Can this code be triggered remotely or only locally.
- Remotely_accessible *bool `json:"remotely_accessible,omitempty"`
- // Is the fuzzed code host only, i.e. test frameworks or support utilities.
- Host_only *bool `json:"host_only,omitempty"`
+ // Whether the code being fuzzed is remotely accessible or requires privileges
+ // to access locally.
+ Vector Vector `json:"vector,omitempty"`
+ // How privileged the service being fuzzed is.
+ Service_privilege ServicePrivilege `json:"service_privilege,omitempty"`
+ // Whether the service being fuzzed handles data from multiple users or only
+ // a single one.
+ Users UserData `json:"users,omitempty"`
+ // Specifies the use state of the code being fuzzed. This state factors into
+ // how an issue is handled.
+ Fuzzed_code_usage FuzzedCodeUsage `json:"fuzzed_code_usage,omitempty"`
+ // Comment describing how we came to these settings for this fuzzer.
+ Config_comment string
+ // Which team to route this to, if it should be routed automatically.
+ Automatically_route_to AutomaticallyRouteTo `json:"automatically_route_to,omitempty"`
// Can third party/untrusted apps supply data to fuzzed code.
Untrusted_data *bool `json:"untrusted_data,omitempty"`
- // Is the code being fuzzed in a privileged, constrained or any other
- // context from:
- // https://source.android.com/security/overview/updates-resources#context_types.
- Privilege_level PrivilegedLevel `json:"privilege_level,omitempty"`
- // Can the fuzzed code isolated or can be called by multiple users/processes.
- Isolated *bool `json:"users_isolation,omitempty"`
- // When code was relaeased or will be released.
+ // When code was released or will be released.
Production_date string `json:"production_date,omitempty"`
// Prevents critical service functionality like phone calls, bluetooth, etc.
Critical *bool `json:"critical,omitempty"`
@@ -134,7 +319,7 @@ type FuzzConfig struct {
Fuzz_on_haiku_host *bool `json:"fuzz_on_haiku_host,omitempty"`
// Component in Google's bug tracking system that bugs should be filed to.
Componentid *int64 `json:"componentid,omitempty"`
- // Hotlists in Google's bug tracking system that bugs should be marked with.
+ // Hotlist(s) in Google's bug tracking system that bugs should be marked with.
Hotlists []string `json:"hotlists,omitempty"`
// Specify whether this fuzz target was submitted by a researcher. Defaults
// to false.
diff --git a/java/OWNERS b/java/OWNERS
deleted file mode 100644
index 5b71b1e35..000000000
--- a/java/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-per-file dexpreopt*.go = ngeoffray@google.com,calin@google.com,skvadrik@google.com
-
-# For metalava team to disable lint checks in platform
-per-file droidstubs.go = aurimas@google.com,emberrose@google.com,sjgilbert@google.com \ No newline at end of file
diff --git a/java/aar.go b/java/aar.go
index a483e13b9..7cdcbae1b 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -219,13 +219,32 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkConte
linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirStrings, "-A "))
linkDeps = append(linkDeps, assetDeps...)
- // SDK version flags
- minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx)
- if err != nil {
- ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
+ // Returns the effective version for {min|target}_sdk_version
+ effectiveVersionString := func(sdkVersion android.SdkSpec, minSdkVersion android.SdkSpec) string {
+ // If {min|target}_sdk_version is current, use sdk_version to determine the effective level
+ // This is necessary for vendor modules.
+ // The effective version does not _only_ depend on {min|target}_sdk_version(level),
+ // but also on the sdk_version (kind+level)
+ if minSdkVersion.ApiLevel.IsCurrent() {
+ ret, err := sdkVersion.EffectiveVersionString(ctx)
+ if err != nil {
+ ctx.ModuleErrorf("invalid sdk_version: %s", err)
+ }
+ return ret
+ }
+ ret, err := minSdkVersion.EffectiveVersionString(ctx)
+ if err != nil {
+ ctx.ModuleErrorf("invalid min_sdk_version: %s", err)
+ }
+ return ret
}
+ // SDK version flags
+ sdkVersion := sdkContext.SdkVersion(ctx)
+ minSdkVersion := effectiveVersionString(sdkVersion, sdkContext.MinSdkVersion(ctx))
linkFlags = append(linkFlags, "--min-sdk-version "+minSdkVersion)
+ // Use minSdkVersion for target-sdk-version, even if `target_sdk_version` is set
+ // This behavior has been copied from Make.
linkFlags = append(linkFlags, "--target-sdk-version "+minSdkVersion)
// Version code
diff --git a/java/app.go b/java/app.go
index 52348086e..1731970b3 100755
--- a/java/app.go
+++ b/java/app.go
@@ -984,8 +984,11 @@ type appTestProperties struct {
// The name of the android_app module that the tests will run against.
Instrumentation_for *string
- // if specified, the instrumentation target package name in the manifest is overwritten by it.
+ // If specified, the instrumentation target package name in the manifest is overwritten by it.
Instrumentation_target_package *string
+
+ // If specified, the mainline module package name in the test config is overwritten by it.
+ Mainline_package_name *string
}
type AndroidTest struct {
@@ -1063,6 +1066,11 @@ func (a *AndroidTest) FixTestConfig(ctx android.ModuleContext, testConfig androi
FlagWithArg("--package-name ", *a.overridableAppProperties.Package_name)
}
+ if a.appTestProperties.Mainline_package_name != nil {
+ fixNeeded = true
+ command.FlagWithArg("--mainline-package-name ", *a.appTestProperties.Mainline_package_name)
+ }
+
if fixNeeded {
rule.Build("fix_test_config", "fix test config")
return fixedConfig
diff --git a/java/app_test.go b/java/app_test.go
index 3fb67c188..5b16cea28 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1005,6 +1005,7 @@ func TestAppSdkVersion(t *testing.T) {
platformSdkInt int
platformSdkCodename string
platformSdkFinal bool
+ minSdkVersionBp string
expectedMinSdkVersion string
platformApis bool
activeCodenames []string
@@ -1052,6 +1053,14 @@ func TestAppSdkVersion(t *testing.T) {
platformSdkCodename: "S",
activeCodenames: []string{"S"},
},
+ {
+ name: "two active SDKs",
+ sdkVersion: "module_current",
+ minSdkVersionBp: "UpsideDownCake",
+ expectedMinSdkVersion: "UpsideDownCake", // And not VanillaIceCream
+ platformSdkCodename: "VanillaIceCream",
+ activeCodenames: []string{"UpsideDownCake", "VanillaIceCream"},
+ },
}
for _, moduleType := range []string{"android_app", "android_library"} {
@@ -1061,12 +1070,17 @@ func TestAppSdkVersion(t *testing.T) {
if test.platformApis {
platformApiProp = "platform_apis: true,"
}
+ minSdkVersionProp := ""
+ if test.minSdkVersionBp != "" {
+ minSdkVersionProp = fmt.Sprintf(` min_sdk_version: "%s",`, test.minSdkVersionBp)
+ }
bp := fmt.Sprintf(`%s {
name: "foo",
srcs: ["a.java"],
sdk_version: "%s",
%s
- }`, moduleType, test.sdkVersion, platformApiProp)
+ %s
+ }`, moduleType, test.sdkVersion, platformApiProp, minSdkVersionProp)
result := android.GroupFixturePreparers(
prepareForJavaTest,
@@ -2330,12 +2344,14 @@ func TestAndroidTest_FixTestConfig(t *testing.T) {
srcs: ["b.java"],
package_name: "com.android.bar.test",
instrumentation_for: "foo",
+ mainline_package_name: "com.android.bar",
}
override_android_test {
name: "baz_test",
base: "foo_test",
package_name: "com.android.baz.test",
+ mainline_package_name: "com.android.baz",
}
`)
@@ -2354,6 +2370,7 @@ func TestAndroidTest_FixTestConfig(t *testing.T) {
expectedFlags: []string{
"--manifest out/soong/.intermediates/bar_test/android_common/manifest_fixer/AndroidManifest.xml",
"--package-name com.android.bar.test",
+ "--mainline-package-name com.android.bar",
},
},
{
@@ -2363,6 +2380,8 @@ func TestAndroidTest_FixTestConfig(t *testing.T) {
"--manifest out/soong/.intermediates/foo_test/android_common_baz_test/manifest_fixer/AndroidManifest.xml",
"--package-name com.android.baz.test",
"--test-file-name baz_test.apk",
+ "out/soong/.intermediates/foo_test/android_common_baz_test/test_config_fixer/AndroidTest.xml",
+ "--mainline-package-name com.android.baz",
},
},
}
diff --git a/java/base.go b/java/base.go
index cce06a4e9..85f4a5e06 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1003,7 +1003,7 @@ func (j *Module) collectJavacFlags(
topLevelDirs[srcFileParts[0]] = true
}
}
- patchPaths = append(patchPaths, android.SortedStringKeys(topLevelDirs)...)
+ patchPaths = append(patchPaths, android.SortedKeys(topLevelDirs)...)
classPath := flags.classpath.FormJavaClassPath("")
if classPath != "" {
@@ -1487,7 +1487,14 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
}
// Dex compilation
var dexOutputFile android.OutputPath
- dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(ctx), implementationAndResourcesJar, jarName)
+ params := &compileDexParams{
+ flags: flags,
+ sdkVersion: j.SdkVersion(ctx),
+ minSdkVersion: j.MinSdkVersion(ctx),
+ classesJar: implementationAndResourcesJar,
+ jarName: jarName,
+ }
+ dexOutputFile = j.dexer.compileDex(ctx, params)
if ctx.Failed() {
return
}
@@ -1838,15 +1845,18 @@ func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu
// Implements android.ApexModule
func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
- sdkSpec := j.MinSdkVersion(ctx)
- if !sdkSpec.Specified() {
+ sdkVersionSpec := j.SdkVersion(ctx)
+ minSdkVersionSpec := j.MinSdkVersion(ctx)
+ if !minSdkVersionSpec.Specified() {
return fmt.Errorf("min_sdk_version is not specified")
}
- if sdkSpec.Kind == android.SdkCore {
+ // If the module is compiling against core (via sdk_version), skip comparison check.
+ if sdkVersionSpec.Kind == android.SdkCore {
return nil
}
- if sdkSpec.ApiLevel.GreaterThan(sdkVersion) {
- return fmt.Errorf("newer SDK(%v)", sdkSpec.ApiLevel)
+ minSdkVersion := minSdkVersionSpec.ApiLevel
+ if minSdkVersion.GreaterThan(sdkVersion) {
+ return fmt.Errorf("newer SDK(%v)", minSdkVersion)
}
return nil
}
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 101d3cad9..c07a94a0b 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -440,7 +440,7 @@ func (i BootclasspathFragmentApexContentInfo) DexBootJarPathForContentModule(mod
return dexJar, nil
} else {
return nil, fmt.Errorf("unknown bootclasspath_fragment content module %s, expected one of %s",
- name, strings.Join(android.SortedStringKeys(i.contentModuleDexJarPaths), ", "))
+ name, strings.Join(android.SortedKeys(i.contentModuleDexJarPaths), ", "))
}
}
@@ -709,7 +709,7 @@ func (b *BootclasspathFragmentModule) getImageConfig(ctx android.EarlyModuleCont
imageName := *imageNamePtr
imageConfig := imageConfigs[imageName]
if imageConfig == nil {
- ctx.PropertyErrorf("image_name", "Unknown image name %q, expected one of %s", imageName, strings.Join(android.SortedStringKeys(imageConfigs), ", "))
+ ctx.PropertyErrorf("image_name", "Unknown image name %q, expected one of %s", imageName, strings.Join(android.SortedKeys(imageConfigs), ", "))
return nil
}
return imageConfig
@@ -1291,7 +1291,7 @@ func (module *PrebuiltBootclasspathFragmentModule) produceBootImageFiles(ctx and
}
return bootImageFiles
} else {
- if profile == nil {
+ if profile == nil && imageConfig.isProfileGuided() {
ctx.ModuleErrorf("Unable to produce boot image files: neither boot image files nor profiles exists in the prebuilt apex")
return bootImageOutputs{}
}
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index 259e977d8..cf81ddb5d 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -111,7 +111,7 @@ func gatherPossibleApexModuleNamesAndStems(ctx android.ModuleContext, contents [
ctx.PropertyErrorf("contents", "%v is not a ModuleWithStem", name)
}
}
- return android.SortedStringKeys(set)
+ return android.SortedKeys(set)
}
// Converts android.ConfiguredJarList into a list of classpathJars for each given classpathType.
diff --git a/java/config/config.go b/java/config/config.go
index 7c22076ae..293eb9230 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -195,6 +195,7 @@ func init() {
pctx.HostBinToolVariable("ManifestMergerCmd", "manifest-merger")
pctx.HostBinToolVariable("Class2NonSdkList", "class2nonsdklist")
+ pctx.HostBinToolVariable("MergeCsvCommand", "merge_csv")
pctx.HostBinToolVariable("HiddenAPI", "hiddenapi")
hostBinToolVariableWithSdkToolsPrebuilt("Aapt2Cmd", "aapt2")
diff --git a/java/dex.go b/java/dex.go
index a8dd37508..7b6a99a8a 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -184,7 +184,7 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8",
"r8Flags", "zipFlags", "tmpJar", "mergeZipsFlags"}, []string{"implicits"})
func (d *dexer) dexCommonFlags(ctx android.ModuleContext,
- minSdkVersion android.SdkSpec) (flags []string, deps android.Paths) {
+ dexParams *compileDexParams) (flags []string, deps android.Paths) {
flags = d.dexProperties.Dxflags
// Translate all the DX flags to D8 ones until all the build files have been migrated
@@ -213,11 +213,11 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext,
// Note: Targets with a min SDK kind of core_platform (e.g., framework.jar) or unspecified (e.g.,
// services.jar), are not classified as stable, which is WAI.
// TODO(b/232073181): Expand to additional min SDK cases after validation.
- if !minSdkVersion.Stable() {
+ if !dexParams.sdkVersion.Stable() {
flags = append(flags, "--android-platform-build")
}
- effectiveVersion, err := minSdkVersion.EffectiveVersion(ctx)
+ effectiveVersion, err := dexParams.minSdkVersion.EffectiveVersion(ctx)
if err != nil {
ctx.PropertyErrorf("min_sdk_version", "%s", err)
}
@@ -340,20 +340,27 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl
return r8Flags, r8Deps
}
-func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, minSdkVersion android.SdkSpec,
- classesJar android.Path, jarName string) android.OutputPath {
+type compileDexParams struct {
+ flags javaBuilderFlags
+ sdkVersion android.SdkSpec
+ minSdkVersion android.SdkSpec
+ classesJar android.Path
+ jarName string
+}
+
+func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParams) android.OutputPath {
// Compile classes.jar into classes.dex and then javalib.jar
- javalibJar := android.PathForModuleOut(ctx, "dex", jarName).OutputPath
+ javalibJar := android.PathForModuleOut(ctx, "dex", dexParams.jarName).OutputPath
outDir := android.PathForModuleOut(ctx, "dex")
- tmpJar := android.PathForModuleOut(ctx, "withres-withoutdex", jarName)
+ tmpJar := android.PathForModuleOut(ctx, "withres-withoutdex", dexParams.jarName)
zipFlags := "--ignore_missing_files"
if proptools.Bool(d.dexProperties.Uncompress_dex) {
zipFlags += " -L 0"
}
- commonFlags, commonDeps := d.dexCommonFlags(ctx, minSdkVersion)
+ commonFlags, commonDeps := d.dexCommonFlags(ctx, dexParams)
// Exclude kotlinc generated files when "exclude_kotlinc_generated_files" is set to true.
mergeZipsFlags := ""
@@ -372,7 +379,7 @@ func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, mi
android.ModuleNameWithPossibleOverride(ctx), "unused.txt")
proguardUsageZip := android.PathForModuleOut(ctx, "proguard_usage.zip")
d.proguardUsageZip = android.OptionalPathForPath(proguardUsageZip)
- r8Flags, r8Deps := d.r8Flags(ctx, flags)
+ r8Flags, r8Deps := d.r8Flags(ctx, dexParams.flags)
r8Deps = append(r8Deps, commonDeps...)
rule := r8
args := map[string]string{
@@ -396,12 +403,12 @@ func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, mi
Description: "r8",
Output: javalibJar,
ImplicitOutputs: android.WritablePaths{proguardDictionary, proguardUsageZip},
- Input: classesJar,
+ Input: dexParams.classesJar,
Implicits: r8Deps,
Args: args,
})
} else {
- d8Flags, d8Deps := d8Flags(flags)
+ d8Flags, d8Deps := d8Flags(dexParams.flags)
d8Deps = append(d8Deps, commonDeps...)
rule := d8
if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_D8") {
@@ -411,7 +418,7 @@ func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, mi
Rule: rule,
Description: "d8",
Output: javalibJar,
- Input: classesJar,
+ Input: dexParams.classesJar,
Implicits: d8Deps,
Args: map[string]string{
"d8Flags": strings.Join(append(commonFlags, d8Flags...), " "),
@@ -423,7 +430,7 @@ func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, mi
})
}
if proptools.Bool(d.dexProperties.Uncompress_dex) {
- alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", jarName).OutputPath
+ alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", dexParams.jarName).OutputPath
TransformZipAlign(ctx, alignedJavalibJar, javalibJar)
javalibJar = alignedJavalibJar
}
diff --git a/java/dex_test.go b/java/dex_test.go
index dc85f9e34..97fc3d0dd 100644
--- a/java/dex_test.go
+++ b/java/dex_test.go
@@ -43,6 +43,7 @@ func TestR8(t *testing.T) {
name: "core_platform_app",
srcs: ["foo.java"],
sdk_version: "core_platform",
+ min_sdk_version: "31",
}
java_library {
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 77cbe9cf4..0ffedf6c4 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -23,10 +23,24 @@ import (
)
type DexpreopterInterface interface {
- IsInstallable() bool // Structs that embed dexpreopter must implement this.
+ // True if the java module is to be dexed and installed on devices.
+ // Structs that embed dexpreopter must implement this.
+ IsInstallable() bool
+
+ // True if dexpreopt is disabled for the java module.
dexpreoptDisabled(ctx android.BaseModuleContext) bool
+
+ // If the java module is to be installed into an APEX, this list contains information about the
+ // dexpreopt outputs to be installed on devices. Note that these dexpreopt outputs are installed
+ // outside of the APEX.
DexpreoptBuiltInstalledForApex() []dexpreopterInstall
+
+ // The Make entries to install the dexpreopt outputs. Derived from
+ // `DexpreoptBuiltInstalledForApex`.
AndroidMkEntriesForApex() []android.AndroidMkEntries
+
+ // See `dexpreopter.outputProfilePathOnHost`.
+ OutputProfilePathOnHost() android.Path
}
type dexpreopterInstall struct {
@@ -77,7 +91,8 @@ func (install dexpreopterInstall) ToMakeEntries() android.AndroidMkEntries {
}
type dexpreopter struct {
- dexpreoptProperties DexpreoptProperties
+ dexpreoptProperties DexpreoptProperties
+ importDexpreoptProperties ImportDexpreoptProperties
installPath android.InstallPath
uncompressedDex bool
@@ -103,6 +118,14 @@ type dexpreopter struct {
// - Dexpreopt post-processing (using dexpreopt artifacts from a prebuilt system image to incrementally
// dexpreopt another partition).
configPath android.WritablePath
+
+ // The path to the profile on host that dexpreopter generates. This is used as the input for
+ // dex2oat.
+ outputProfilePathOnHost android.Path
+
+ // The path to the profile that dexpreopter accepts. It must be in the binary format. If this is
+ // set, it overrides the profile settings in `dexpreoptProperties`.
+ inputProfilePathOnHost android.Path
}
type DexpreoptProperties struct {
@@ -123,6 +146,18 @@ type DexpreoptProperties struct {
// profile location set by PRODUCT_DEX_PREOPT_PROFILE_DIR, or empty if not found.
Profile *string `android:"path"`
}
+
+ Dex_preopt_result struct {
+ // True if profile-guided optimization is actually enabled.
+ Profile_guided bool
+ } `blueprint:"mutated"`
+}
+
+type ImportDexpreoptProperties struct {
+ Dex_preopt struct {
+ // If true, use the profile in the prebuilt APEX to guide optimization. Defaults to false.
+ Profile_guided *bool
+ }
}
func init() {
@@ -180,9 +215,8 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx))
if isApexVariant(ctx) {
- // Don't preopt APEX variant module unless the module is an APEX system server jar and we are
- // building the entire system image.
- if !isApexSystemServerJar || ctx.Config().UnbundledBuild() {
+ // Don't preopt APEX variant module unless the module is an APEX system server jar.
+ if !isApexSystemServerJar {
return true
}
} else {
@@ -259,6 +293,12 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
isSystemServerJar := global.AllSystemServerJars(ctx).ContainsJar(moduleName(ctx))
bootImage := defaultBootImageConfig(ctx)
+ // When `global.PreoptWithUpdatableBcp` is true, `bcpForDexpreopt` below includes the mainline
+ // boot jars into bootclasspath, so we should include the mainline boot image as well because it's
+ // generated from those jars.
+ if global.PreoptWithUpdatableBcp {
+ bootImage = mainlineBootImageConfig(ctx)
+ }
dexFiles, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp)
targets := ctx.MultiTargets()
@@ -292,7 +332,9 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
var profileClassListing android.OptionalPath
var profileBootListing android.OptionalPath
profileIsTextListing := false
- if BoolDefault(d.dexpreoptProperties.Dex_preopt.Profile_guided, true) {
+ if d.inputProfilePathOnHost != nil {
+ profileClassListing = android.OptionalPathForPath(d.inputProfilePathOnHost)
+ } else if BoolDefault(d.dexpreoptProperties.Dex_preopt.Profile_guided, true) && !forPrebuiltApex(ctx) {
// If dex_preopt.profile_guided is not set, default it based on the existence of the
// dexprepot.profile option or the profile class listing.
if String(d.dexpreoptProperties.Dex_preopt.Profile) != "" {
@@ -307,6 +349,8 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
}
}
+ d.dexpreoptProperties.Dex_preopt_result.Profile_guided = profileClassListing.Valid()
+
// Full dexpreopt config, used to create dexpreopt build rules.
dexpreoptConfig := &dexpreopt.ModuleConfig{
Name: moduleName(ctx),
@@ -368,21 +412,29 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
installBase := filepath.Base(install.To)
arch := filepath.Base(installDir)
installPath := android.PathForModuleInPartitionInstall(ctx, "", installDir)
+ isProfile := strings.HasSuffix(installBase, ".prof")
+
+ if isProfile {
+ d.outputProfilePathOnHost = install.From
+ }
if isApexSystemServerJar {
- // APEX variants of java libraries are hidden from Make, so their dexpreopt
- // outputs need special handling. Currently, for APEX variants of java
- // libraries, only those in the system server classpath are handled here.
- // Preopting of boot classpath jars in the ART APEX are handled in
- // java/dexpreopt_bootjars.go, and other APEX jars are not preopted.
- // The installs will be handled by Make as sub-modules of the java library.
- d.builtInstalledForApex = append(d.builtInstalledForApex, dexpreopterInstall{
- name: arch + "-" + installBase,
- moduleName: moduleName(ctx),
- outputPathOnHost: install.From,
- installDirOnDevice: installPath,
- installFileOnDevice: installBase,
- })
+ // Profiles are handled separately because they are installed into the APEX.
+ if !isProfile {
+ // APEX variants of java libraries are hidden from Make, so their dexpreopt
+ // outputs need special handling. Currently, for APEX variants of java
+ // libraries, only those in the system server classpath are handled here.
+ // Preopting of boot classpath jars in the ART APEX are handled in
+ // java/dexpreopt_bootjars.go, and other APEX jars are not preopted.
+ // The installs will be handled by Make as sub-modules of the java library.
+ d.builtInstalledForApex = append(d.builtInstalledForApex, dexpreopterInstall{
+ name: arch + "-" + installBase,
+ moduleName: moduleName(ctx),
+ outputPathOnHost: install.From,
+ installDirOnDevice: installPath,
+ installFileOnDevice: installBase,
+ })
+ }
} else if !d.preventInstall {
ctx.InstallFile(installPath, installBase, install.From)
}
@@ -404,3 +456,7 @@ func (d *dexpreopter) AndroidMkEntriesForApex() []android.AndroidMkEntries {
}
return entries
}
+
+func (d *dexpreopter) OutputProfilePathOnHost() android.Path {
+ return d.outputProfilePathOnHost
+}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 3effff649..373b478c8 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -16,6 +16,7 @@ package java
import (
"path/filepath"
+ "sort"
"strings"
"android/soong/android"
@@ -287,6 +288,9 @@ type bootImageConfig struct {
// Path of the preloaded classes file.
preloadedClassesFile string
+
+ // The "--compiler-filter" argument.
+ compilerFilter string
}
// Target-dependent description of a boot image.
@@ -309,17 +313,17 @@ type bootImageVariant struct {
// All the files that constitute this image variant, i.e. .art, .oat and .vdex files.
imagesDeps android.OutputPaths
- // The path to the primary image variant's imagePathOnHost field, where primary image variant
+ // The path to the base image variant's imagePathOnHost field, where base image variant
// means the image variant that this extends.
//
// This is only set for a variant of an image that extends another image.
- primaryImages android.OutputPath
+ baseImages android.OutputPaths
- // The paths to the primary image variant's imagesDeps field, where primary image variant
+ // The paths to the base image variant's imagesDeps field, where base image variant
// means the image variant that this extends.
//
// This is only set for a variant of an image that extends another image.
- primaryImagesDeps android.Paths
+ baseImagesDeps android.Paths
// Rules which should be used in make to install the outputs on host.
//
@@ -443,6 +447,10 @@ func (image *bootImageVariant) imageLocations() (imageLocationsOnHost []string,
append(imageLocationsOnDevice, dexpreopt.PathStringToLocation(image.imagePathOnDevice, image.target.Arch.ArchType))
}
+func (image *bootImageConfig) isProfileGuided() bool {
+ return image.compilerFilter == "speed-profile"
+}
+
func dexpreoptBootJarsFactory() android.SingletonModule {
m := &dexpreoptBootJars{}
android.InitAndroidModule(m)
@@ -504,8 +512,13 @@ func (d *dexpreoptBootJars) GenerateSingletonBuildActions(ctx android.SingletonC
defaultImageConfig := defaultBootImageConfig(ctx)
d.defaultBootImage = defaultImageConfig
- artBootImageConfig := artBootImageConfig(ctx)
- d.otherImages = []*bootImageConfig{artBootImageConfig}
+ imageConfigs := genBootImageConfigs(ctx)
+ d.otherImages = make([]*bootImageConfig, 0, len(imageConfigs)-1)
+ for _, config := range imageConfigs {
+ if config != defaultImageConfig {
+ d.otherImages = append(d.otherImages, config)
+ }
+ }
}
// shouldBuildBootImages determines whether boot images should be built.
@@ -525,8 +538,8 @@ func shouldBuildBootImages(config android.Config, global *dexpreopt.GlobalConfig
func copyBootJarsToPredefinedLocations(ctx android.ModuleContext, srcBootDexJarsByModule bootDexJarByModule, dstBootJarsByModule map[string]android.WritablePath) {
// Create the super set of module names.
names := []string{}
- names = append(names, android.SortedStringKeys(srcBootDexJarsByModule)...)
- names = append(names, android.SortedStringKeys(dstBootJarsByModule)...)
+ names = append(names, android.SortedKeys(srcBootDexJarsByModule)...)
+ names = append(names, android.SortedKeys(dstBootJarsByModule)...)
names = android.SortedUniqueStrings(names)
for _, name := range names {
src := srcBootDexJarsByModule[name]
@@ -701,9 +714,11 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p
}
if image.extends != nil {
- // It is a boot image extension, so it needs the boot image it depends on (in this case the
- // primary ART APEX image).
- artImage := image.primaryImages
+ // It is a boot image extension, so it needs the boot images that it depends on.
+ baseImageLocations := make([]string, 0, len(image.baseImages))
+ for _, image := range image.baseImages {
+ baseImageLocations = append(baseImageLocations, dexpreopt.PathToLocation(image, arch))
+ }
cmd.
Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", image.dexLocationsDeps, ":").
@@ -711,21 +726,23 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p
// dex2oat will reconstruct the path to the actual file when it needs it. As the actual path
// to the file cannot be passed to the command make sure to add the actual path as an Implicit
// dependency to ensure that it is built before the command runs.
- FlagWithArg("--boot-image=", dexpreopt.PathToLocation(artImage, arch)).Implicit(artImage).
+ FlagWithList("--boot-image=", baseImageLocations, ":").Implicits(image.baseImages.Paths()).
// Similarly, the dex2oat tool will automatically find the paths to other files in the base
// boot image so make sure to add them as implicit dependencies to ensure that they are built
// before this command is run.
- Implicits(image.primaryImagesDeps)
+ Implicits(image.baseImagesDeps)
} else {
// It is a primary image, so it needs a base address.
cmd.FlagWithArg("--base=", ctx.Config().LibartImgDeviceBaseAddress())
}
- // We always expect a preloaded classes file to be available. However, if we cannot find it, it's
- // OK to not pass the flag to dex2oat.
- preloadedClassesPath := android.ExistentPathForSource(ctx, image.preloadedClassesFile)
- if preloadedClassesPath.Valid() {
- cmd.FlagWithInput("--preloaded-classes=", preloadedClassesPath.Path())
+ if len(image.preloadedClassesFile) > 0 {
+ // We always expect a preloaded classes file to be available. However, if we cannot find it, it's
+ // OK to not pass the flag to dex2oat.
+ preloadedClassesPath := android.ExistentPathForSource(ctx, image.preloadedClassesFile)
+ if preloadedClassesPath.Valid() {
+ cmd.FlagWithInput("--preloaded-classes=", preloadedClassesPath.Path())
+ }
}
cmd.
@@ -745,6 +762,12 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p
Flag("--force-determinism").
Flag("--abort-on-hard-verifier-error")
+ // If the image is profile-guided but the profile is disabled, we omit "--compiler-filter" to
+ // leave the decision to dex2oat to pick the compiler filter.
+ if !(image.isProfileGuided() && global.DisableGenerateProfile) {
+ cmd.FlagWithArg("--compiler-filter=", image.compilerFilter)
+ }
+
// Use the default variant/features for host builds.
// The map below contains only device CPU info (which might be x86 on some devices).
if image.target.Os == android.Android {
@@ -828,6 +851,10 @@ It is likely that the boot classpath is inconsistent.
Rebuild with ART_BOOT_IMAGE_EXTRA_ARGS="--runtime-arg -verbose:verifier" to see verification errors.`
func bootImageProfileRule(ctx android.ModuleContext, image *bootImageConfig) android.WritablePath {
+ if !image.isProfileGuided() {
+ return nil
+ }
+
globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
global := dexpreopt.GetGlobalConfig(ctx)
@@ -1007,6 +1034,8 @@ func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) {
ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICE"+current.name, strings.Join(imageLocationsOnDevice, ":"))
ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+current.name, current.zip.String())
}
+ // Ensure determinism.
+ sort.Strings(imageNames)
ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(imageNames, " "))
}
}
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 4d0bd09c6..117b660b7 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -44,6 +44,8 @@ var (
bootImageConfigRawKey = android.NewOnceKey("bootImageConfigRaw")
artBootImageName = "art"
frameworkBootImageName = "boot"
+ mainlineBootImageName = "mainline"
+ bootImageStem = "boot"
)
func genBootImageConfigRaw(ctx android.PathContext) map[string]*bootImageConfig {
@@ -52,35 +54,49 @@ func genBootImageConfigRaw(ctx android.PathContext) map[string]*bootImageConfig
artModules := global.ArtApexJars
frameworkModules := global.BootJars.RemoveList(artModules)
+ mainlineBcpModules := global.ApexBootJars
+ frameworkSubdir := "system/framework"
// ART config for the primary boot image in the ART apex.
// It includes the Core Libraries.
artCfg := bootImageConfig{
name: artBootImageName,
- stem: "boot",
+ stem: bootImageStem,
installDirOnHost: "apex/art_boot_images/javalib",
- installDirOnDevice: "system/framework",
+ installDirOnDevice: frameworkSubdir,
profileInstallPathInApex: "etc/boot-image.prof",
modules: artModules,
preloadedClassesFile: "art/build/boot/preloaded-classes",
+ compilerFilter: "speed-profile",
}
// Framework config for the boot image extension.
// It includes framework libraries and depends on the ART config.
- frameworkSubdir := "system/framework"
frameworkCfg := bootImageConfig{
extends: &artCfg,
name: frameworkBootImageName,
- stem: "boot",
+ stem: bootImageStem,
installDirOnHost: frameworkSubdir,
installDirOnDevice: frameworkSubdir,
modules: frameworkModules,
preloadedClassesFile: "frameworks/base/config/preloaded-classes",
+ compilerFilter: "speed-profile",
+ }
+
+ mainlineCfg := bootImageConfig{
+ extends: &frameworkCfg,
+ name: mainlineBootImageName,
+ stem: bootImageStem,
+ installDirOnHost: frameworkSubdir,
+ installDirOnDevice: frameworkSubdir,
+ modules: mainlineBcpModules,
+ compilerFilter: "verify",
}
return map[string]*bootImageConfig{
artBootImageName: &artCfg,
frameworkBootImageName: &frameworkCfg,
+ mainlineBootImageName: &mainlineCfg,
}
}).(map[string]*bootImageConfig)
}
@@ -92,10 +108,7 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
configs := genBootImageConfigRaw(ctx)
- artCfg := configs[artBootImageName]
- frameworkCfg := configs[frameworkBootImageName]
- // common to all configs
for _, c := range configs {
c.dir = deviceDir.Join(ctx, "dex_"+c.name+"jars")
c.symbolsDir = deviceDir.Join(ctx, "dex_"+c.name+"jars_unstripped")
@@ -131,18 +144,42 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
c.zip = c.dir.Join(ctx, c.name+".zip")
}
- // specific to the framework config
- frameworkCfg.dexPathsDeps = append(artCfg.dexPathsDeps, frameworkCfg.dexPathsDeps...)
- for i := range targets {
- frameworkCfg.variants[i].primaryImages = artCfg.variants[i].imagePathOnHost
- frameworkCfg.variants[i].primaryImagesDeps = artCfg.variants[i].imagesDeps.Paths()
- frameworkCfg.variants[i].dexLocationsDeps = append(artCfg.variants[i].dexLocations, frameworkCfg.variants[i].dexLocationsDeps...)
+ visited := make(map[string]bool)
+ for _, c := range configs {
+ calculateDepsRecursive(c, targets, visited)
}
return configs
}).(map[string]*bootImageConfig)
}
+// calculateDepsRecursive calculates the dependencies of the given boot image config and all its
+// ancestors, if they are not visited.
+// The boot images are supposed to form a tree, where the root is the primary boot image. We do not
+// expect loops (e.g., A extends B, B extends C, C extends A), and we let them crash soong with a
+// stack overflow.
+// Note that a boot image config only has a pointer to the parent, not to children. Therefore, we
+// first go up through the parent chain, and then go back down to visit every code along the path.
+// `visited` is a map where a key is a boot image name and the value indicates whether the boot
+// image config is visited. The boot image names are guaranteed to be unique because they come from
+// `genBootImageConfigRaw` above, which also returns a map and would fail in the first place if the
+// names were not unique.
+func calculateDepsRecursive(c *bootImageConfig, targets []android.Target, visited map[string]bool) {
+ if c.extends == nil || visited[c.name] {
+ return
+ }
+ if c.extends.extends != nil {
+ calculateDepsRecursive(c.extends, targets, visited)
+ }
+ visited[c.name] = true
+ c.dexPathsDeps = android.Concat(c.extends.dexPathsDeps, c.dexPathsDeps)
+ for i := range targets {
+ c.variants[i].baseImages = android.Concat(c.extends.variants[i].baseImages, android.OutputPaths{c.extends.variants[i].imagePathOnHost})
+ c.variants[i].baseImagesDeps = android.Concat(c.extends.variants[i].baseImagesDeps, c.extends.variants[i].imagesDeps.Paths())
+ c.variants[i].dexLocationsDeps = android.Concat(c.extends.variants[i].dexLocationsDeps, c.variants[i].dexLocationsDeps)
+ }
+}
+
func artBootImageConfig(ctx android.PathContext) *bootImageConfig {
return genBootImageConfigs(ctx)[artBootImageName]
}
@@ -151,6 +188,10 @@ func defaultBootImageConfig(ctx android.PathContext) *bootImageConfig {
return genBootImageConfigs(ctx)[frameworkBootImageName]
}
+func mainlineBootImageConfig(ctx android.PathContext) *bootImageConfig {
+ return genBootImageConfigs(ctx)[mainlineBootImageName]
+}
+
// Apex boot config allows to access build/install paths of apex boot jars without going
// through the usual trouble of registering dependencies on those modules and extracting build paths
// from those dependencies.
diff --git a/java/dexpreopt_config_test.go b/java/dexpreopt_config_test.go
index b704d09d2..cd7f295c8 100644
--- a/java/dexpreopt_config_test.go
+++ b/java/dexpreopt_config_test.go
@@ -28,8 +28,10 @@ func TestBootImageConfig(t *testing.T) {
result := android.GroupFixturePreparers(
PrepareForBootImageConfigTest,
+ PrepareApexBootJarConfigs,
).RunTest(t)
CheckArtBootImageConfig(t, result)
CheckFrameworkBootImageConfig(t, result)
+ CheckMainlineBootImageConfig(t, result)
}
diff --git a/java/dexpreopt_config_testing.go b/java/dexpreopt_config_testing.go
index 1c236d8af..c27f4c6da 100644
--- a/java/dexpreopt_config_testing.go
+++ b/java/dexpreopt_config_testing.go
@@ -39,6 +39,78 @@ var PrepareForBootImageConfigTest = android.GroupFixturePreparers(
FixtureConfigureBootJars("com.android.art:core1", "com.android.art:core2", "platform:framework"),
)
+var PrepareApexBootJarConfigs = FixtureConfigureApexBootJars(
+ "com.android.foo:framework-foo", "com.android.bar:framework-bar")
+
+var PrepareApexBootJarConfigsAndModules = android.GroupFixturePreparers(
+ PrepareApexBootJarConfigs,
+ prepareApexBootJarModule("com.android.foo", "framework-foo"),
+ prepareApexBootJarModule("com.android.bar", "framework-bar"),
+)
+
+var ApexBootJarFragmentsForPlatformBootclasspath = fmt.Sprintf(`
+ {
+ apex: "%[1]s",
+ module: "%[1]s-bootclasspathfragment",
+ },
+ {
+ apex: "%[2]s",
+ module: "%[2]s-bootclasspathfragment",
+ },
+`, "com.android.foo", "com.android.bar")
+
+var ApexBootJarDexJarPaths = []string{
+ "out/soong/.intermediates/packages/modules/com.android.bar/framework-bar/android_common_apex10000/aligned/framework-bar.jar",
+ "out/soong/.intermediates/packages/modules/com.android.foo/framework-foo/android_common_apex10000/aligned/framework-foo.jar",
+}
+
+func prepareApexBootJarModule(apexName string, moduleName string) android.FixturePreparer {
+ moduleSourceDir := fmt.Sprintf("packages/modules/%s", apexName)
+ return android.GroupFixturePreparers(
+ android.FixtureAddTextFile(moduleSourceDir+"/Android.bp", fmt.Sprintf(`
+ apex {
+ name: "%[1]s",
+ key: "%[1]s.key",
+ bootclasspath_fragments: [
+ "%[1]s-bootclasspathfragment",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "%[1]s.key",
+ public_key: "%[1]s.avbpubkey",
+ private_key: "%[1]s.pem",
+ }
+
+ bootclasspath_fragment {
+ name: "%[1]s-bootclasspathfragment",
+ contents: ["%[2]s"],
+ apex_available: ["%[1]s"],
+ hidden_api: {
+ split_packages: ["*"],
+ },
+ }
+
+ java_library {
+ name: "%[2]s",
+ srcs: ["%[2]s.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ apex_available: ["%[1]s"],
+ }
+ `, apexName, moduleName)),
+ android.FixtureMergeMockFs(android.MockFS{
+ fmt.Sprintf("%s/apex_manifest.json", moduleSourceDir): nil,
+ fmt.Sprintf("%s/%s.avbpubkey", moduleSourceDir, apexName): nil,
+ fmt.Sprintf("%s/%s.pem", moduleSourceDir, apexName): nil,
+ fmt.Sprintf("system/sepolicy/apex/%s-file_contexts", apexName): nil,
+ fmt.Sprintf("%s/%s.java", moduleSourceDir, moduleName): nil,
+ }),
+ )
+}
+
// normalizedInstall represents a android.RuleBuilderInstall that has been normalized to remove
// test specific parts of the From path.
type normalizedInstall struct {
@@ -100,8 +172,8 @@ type expectedVariant struct {
imagePathOnHost string
imagePathOnDevice string
imagesDeps []string
- primaryImages string
- primaryImagesDeps []string
+ baseImages []string
+ baseImagesDeps []string
// Mutated fields
installs []normalizedInstall
@@ -413,8 +485,8 @@ func checkFrameworkBootImageConfig(t *testing.T, result *android.TestResult, mut
"out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.oat",
"out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.vdex",
},
- primaryImages: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
- primaryImagesDeps: []string{
+ baseImages: []string{"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art"},
+ baseImagesDeps: []string{
"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat",
"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex",
@@ -461,8 +533,8 @@ func checkFrameworkBootImageConfig(t *testing.T, result *android.TestResult, mut
"out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.oat",
"out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.vdex",
},
- primaryImages: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
- primaryImagesDeps: []string{
+ baseImages: []string{"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art"},
+ baseImagesDeps: []string{
"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat",
"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex",
@@ -509,8 +581,8 @@ func checkFrameworkBootImageConfig(t *testing.T, result *android.TestResult, mut
"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat",
"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex",
},
- primaryImages: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
- primaryImagesDeps: []string{
+ baseImages: []string{"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art"},
+ baseImagesDeps: []string{
"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat",
"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex",
@@ -557,8 +629,8 @@ func checkFrameworkBootImageConfig(t *testing.T, result *android.TestResult, mut
"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat",
"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex",
},
- primaryImages: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
- primaryImagesDeps: []string{
+ baseImages: []string{"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art"},
+ baseImagesDeps: []string{
"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat",
"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex",
@@ -601,6 +673,366 @@ func checkFrameworkBootImageConfig(t *testing.T, result *android.TestResult, mut
checkBootImageConfig(t, imageConfig, mutated, expected)
}
+// getMainlineImageConfig gets the framework bootImageConfig that was created during the test.
+func getMainlineImageConfig(result *android.TestResult) *bootImageConfig {
+ pathCtx := &android.TestPathContext{TestResult: result}
+ imageConfig := mainlineBootImageConfig(pathCtx)
+ return imageConfig
+}
+
+// CheckMainlineBootImageConfig checks the status of the fields of the bootImageConfig and
+// bootImageVariant structures that are returned from mainlineBootImageConfig.
+//
+// This is before any fields are mutated.
+func CheckMainlineBootImageConfig(t *testing.T, result *android.TestResult) {
+ expectedLicenseMetadataFile := ""
+ imageConfig := getMainlineImageConfig(result)
+
+ expected := &expectedConfig{
+ name: "mainline",
+ stem: "boot",
+ dir: "out/soong/test_device/dex_mainlinejars",
+ symbolsDir: "out/soong/test_device/dex_mainlinejars_unstripped",
+ installDirOnDevice: "system/framework",
+ installDirOnHost: "system/framework",
+ profileInstallPathInApex: "",
+ modules: android.CreateTestConfiguredJarList([]string{
+ "com.android.foo:framework-foo",
+ "com.android.bar:framework-bar",
+ }),
+ dexPaths: []string{
+ "out/soong/test_device/dex_mainlinejars_input/framework-foo.jar",
+ "out/soong/test_device/dex_mainlinejars_input/framework-bar.jar",
+ },
+ dexPathsDeps: []string{
+ "out/soong/test_device/dex_artjars_input/core1.jar",
+ "out/soong/test_device/dex_artjars_input/core2.jar",
+ "out/soong/test_device/dex_bootjars_input/framework.jar",
+ "out/soong/test_device/dex_mainlinejars_input/framework-foo.jar",
+ "out/soong/test_device/dex_mainlinejars_input/framework-bar.jar",
+ },
+ zip: "out/soong/test_device/dex_mainlinejars/mainline.zip",
+ variants: []*expectedVariant{
+ {
+ archType: android.Arm64,
+ dexLocations: []string{
+ "/apex/com.android.foo/javalib/framework-foo.jar",
+ "/apex/com.android.bar/javalib/framework-bar.jar",
+ },
+ dexLocationsDeps: []string{
+ "/apex/com.android.art/javalib/core1.jar",
+ "/apex/com.android.art/javalib/core2.jar",
+ "/system/framework/framework.jar",
+ "/apex/com.android.foo/javalib/framework-foo.jar",
+ "/apex/com.android.bar/javalib/framework-bar.jar",
+ },
+ imagePathOnHost: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art",
+ imagePathOnDevice: "/system/framework/arm64/boot-framework-foo.art",
+ imagesDeps: []string{
+ "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art",
+ "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.oat",
+ "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.vdex",
+ "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-bar.art",
+ "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-bar.oat",
+ "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-bar.vdex",
+ },
+ baseImages: []string{
+ "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
+ "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art",
+ },
+ baseImagesDeps: []string{
+ "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
+ "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat",
+ "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex",
+ "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art",
+ "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat",
+ "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex",
+ "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art",
+ "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.oat",
+ "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.vdex",
+ },
+ installs: []normalizedInstall{
+ {
+ from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art",
+ to: "/system/framework/arm64/boot-framework-foo.art",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.oat",
+ to: "/system/framework/arm64/boot-framework-foo.oat",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-bar.art",
+ to: "/system/framework/arm64/boot-framework-bar.art",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-bar.oat",
+ to: "/system/framework/arm64/boot-framework-bar.oat",
+ },
+ },
+ vdexInstalls: []normalizedInstall{
+ {
+ from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.vdex",
+ to: "/system/framework/arm64/boot-framework-foo.vdex",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-bar.vdex",
+ to: "/system/framework/arm64/boot-framework-bar.vdex",
+ },
+ },
+ unstrippedInstalls: []normalizedInstall{
+ {
+ from: "out/soong/test_device/dex_mainlinejars_unstripped/android/system/framework/arm64/boot-framework-foo.oat",
+ to: "/system/framework/arm64/boot-framework-foo.oat",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars_unstripped/android/system/framework/arm64/boot-framework-bar.oat",
+ to: "/system/framework/arm64/boot-framework-bar.oat",
+ },
+ },
+ licenseMetadataFile: expectedLicenseMetadataFile,
+ },
+ {
+ archType: android.Arm,
+ dexLocations: []string{
+ "/apex/com.android.foo/javalib/framework-foo.jar",
+ "/apex/com.android.bar/javalib/framework-bar.jar",
+ },
+ dexLocationsDeps: []string{
+ "/apex/com.android.art/javalib/core1.jar",
+ "/apex/com.android.art/javalib/core2.jar",
+ "/system/framework/framework.jar",
+ "/apex/com.android.foo/javalib/framework-foo.jar",
+ "/apex/com.android.bar/javalib/framework-bar.jar",
+ },
+ imagePathOnHost: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.art",
+ imagePathOnDevice: "/system/framework/arm/boot-framework-foo.art",
+ imagesDeps: []string{
+ "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.art",
+ "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.oat",
+ "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.vdex",
+ "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-bar.art",
+ "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-bar.oat",
+ "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-bar.vdex",
+ },
+ baseImages: []string{
+ "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
+ "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art",
+ },
+ baseImagesDeps: []string{
+ "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
+ "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat",
+ "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex",
+ "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art",
+ "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat",
+ "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex",
+ "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art",
+ "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.oat",
+ "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.vdex",
+ },
+ installs: []normalizedInstall{
+ {
+ from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.art",
+ to: "/system/framework/arm/boot-framework-foo.art",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.oat",
+ to: "/system/framework/arm/boot-framework-foo.oat",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-bar.art",
+ to: "/system/framework/arm/boot-framework-bar.art",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-bar.oat",
+ to: "/system/framework/arm/boot-framework-bar.oat",
+ },
+ },
+ vdexInstalls: []normalizedInstall{
+ {
+ from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.vdex",
+ to: "/system/framework/arm/boot-framework-foo.vdex",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-bar.vdex",
+ to: "/system/framework/arm/boot-framework-bar.vdex",
+ },
+ },
+ unstrippedInstalls: []normalizedInstall{
+ {
+ from: "out/soong/test_device/dex_mainlinejars_unstripped/android/system/framework/arm/boot-framework-foo.oat",
+ to: "/system/framework/arm/boot-framework-foo.oat",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars_unstripped/android/system/framework/arm/boot-framework-bar.oat",
+ to: "/system/framework/arm/boot-framework-bar.oat",
+ },
+ },
+ licenseMetadataFile: expectedLicenseMetadataFile,
+ },
+ {
+ archType: android.X86_64,
+ dexLocations: []string{
+ "host/linux-x86/apex/com.android.foo/javalib/framework-foo.jar",
+ "host/linux-x86/apex/com.android.bar/javalib/framework-bar.jar",
+ },
+ dexLocationsDeps: []string{
+ "host/linux-x86/apex/com.android.art/javalib/core1.jar",
+ "host/linux-x86/apex/com.android.art/javalib/core2.jar",
+ "host/linux-x86/system/framework/framework.jar",
+ "host/linux-x86/apex/com.android.foo/javalib/framework-foo.jar",
+ "host/linux-x86/apex/com.android.bar/javalib/framework-bar.jar",
+ },
+ imagePathOnHost: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art",
+ imagePathOnDevice: "/system/framework/x86_64/boot-framework-foo.art",
+ imagesDeps: []string{
+ "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art",
+ "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.oat",
+ "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.vdex",
+ "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-bar.art",
+ "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-bar.oat",
+ "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-bar.vdex",
+ },
+ baseImages: []string{
+ "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
+ "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art",
+ },
+ baseImagesDeps: []string{
+ "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
+ "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat",
+ "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex",
+ "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art",
+ "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
+ "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex",
+ "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art",
+ "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat",
+ "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex",
+ },
+ installs: []normalizedInstall{
+ {
+ from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art",
+ to: "/system/framework/x86_64/boot-framework-foo.art",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.oat",
+ to: "/system/framework/x86_64/boot-framework-foo.oat",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-bar.art",
+ to: "/system/framework/x86_64/boot-framework-bar.art",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-bar.oat",
+ to: "/system/framework/x86_64/boot-framework-bar.oat",
+ },
+ },
+ vdexInstalls: []normalizedInstall{
+ {
+ from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.vdex",
+ to: "/system/framework/x86_64/boot-framework-foo.vdex",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-bar.vdex",
+ to: "/system/framework/x86_64/boot-framework-bar.vdex",
+ },
+ },
+ unstrippedInstalls: []normalizedInstall{
+ {
+ from: "out/soong/test_device/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86_64/boot-framework-foo.oat",
+ to: "/system/framework/x86_64/boot-framework-foo.oat",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86_64/boot-framework-bar.oat",
+ to: "/system/framework/x86_64/boot-framework-bar.oat",
+ },
+ },
+ licenseMetadataFile: expectedLicenseMetadataFile,
+ },
+ {
+ archType: android.X86,
+ dexLocations: []string{
+ "host/linux-x86/apex/com.android.foo/javalib/framework-foo.jar",
+ "host/linux-x86/apex/com.android.bar/javalib/framework-bar.jar",
+ },
+ dexLocationsDeps: []string{
+ "host/linux-x86/apex/com.android.art/javalib/core1.jar",
+ "host/linux-x86/apex/com.android.art/javalib/core2.jar",
+ "host/linux-x86/system/framework/framework.jar",
+ "host/linux-x86/apex/com.android.foo/javalib/framework-foo.jar",
+ "host/linux-x86/apex/com.android.bar/javalib/framework-bar.jar",
+ },
+ imagePathOnHost: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art",
+ imagePathOnDevice: "/system/framework/x86/boot-framework-foo.art",
+ imagesDeps: []string{
+ "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art",
+ "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.oat",
+ "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.vdex",
+ "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-bar.art",
+ "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-bar.oat",
+ "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-bar.vdex",
+ },
+ baseImages: []string{
+ "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
+ "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art",
+ },
+ baseImagesDeps: []string{
+ "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
+ "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat",
+ "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex",
+ "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art",
+ "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat",
+ "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex",
+ "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art",
+ "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat",
+ "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex",
+ },
+ installs: []normalizedInstall{
+ {
+ from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art",
+ to: "/system/framework/x86/boot-framework-foo.art",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.oat",
+ to: "/system/framework/x86/boot-framework-foo.oat",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-bar.art",
+ to: "/system/framework/x86/boot-framework-bar.art",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-bar.oat",
+ to: "/system/framework/x86/boot-framework-bar.oat",
+ },
+ },
+ vdexInstalls: []normalizedInstall{
+ {
+ from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.vdex",
+ to: "/system/framework/x86/boot-framework-foo.vdex",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-bar.vdex",
+ to: "/system/framework/x86/boot-framework-bar.vdex",
+ },
+ },
+ unstrippedInstalls: []normalizedInstall{
+ {
+ from: "out/soong/test_device/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86/boot-framework-foo.oat",
+ to: "/system/framework/x86/boot-framework-foo.oat",
+ },
+ {
+ from: "out/soong/test_device/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86/boot-framework-bar.oat",
+ to: "/system/framework/x86/boot-framework-bar.oat",
+ },
+ },
+ licenseMetadataFile: expectedLicenseMetadataFile,
+ },
+ },
+ profileInstalls: []normalizedInstall{},
+ profileLicenseMetadataFile: expectedLicenseMetadataFile,
+ }
+
+ checkBootImageConfig(t, imageConfig, false, expected)
+}
+
// clearMutatedFields clears fields in the expectedConfig that correspond to fields in the
// bootImageConfig/bootImageVariant structs which are mutated outside the call to
// genBootImageConfigs.
@@ -664,8 +1096,8 @@ func nestedCheckBootImageConfig(t *testing.T, imageConfig *bootImageConfig, expe
android.AssertPathRelativeToTopEquals(t, "imagePathOnHost", expectedVariant.imagePathOnHost, variant.imagePathOnHost)
android.AssertStringEquals(t, "imagePathOnDevice", expectedVariant.imagePathOnDevice, variant.imagePathOnDevice)
android.AssertPathsRelativeToTopEquals(t, "imagesDeps", expectedVariant.imagesDeps, variant.imagesDeps.Paths())
- android.AssertPathRelativeToTopEquals(t, "primaryImages", expectedVariant.primaryImages, variant.primaryImages)
- android.AssertPathsRelativeToTopEquals(t, "primaryImagesDeps", expectedVariant.primaryImagesDeps, variant.primaryImagesDeps)
+ android.AssertPathsRelativeToTopEquals(t, "baseImages", expectedVariant.baseImages, variant.baseImages.Paths())
+ android.AssertPathsRelativeToTopEquals(t, "baseImagesDeps", expectedVariant.baseImagesDeps, variant.baseImagesDeps)
assertInstallsEqual(t, "installs", expectedVariant.installs, variant.installs)
assertInstallsEqual(t, "vdexInstalls", expectedVariant.vdexInstalls, variant.vdexInstalls)
assertInstallsEqual(t, "unstrippedInstalls", expectedVariant.unstrippedInstalls, variant.unstrippedInstalls)
@@ -712,6 +1144,10 @@ DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_arm=out/soong/test_device/dex_bootjars/andr
DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_arm64=out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art:/system/framework/arm64/boot-framework.art out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.oat:/system/framework/arm64/boot-framework.oat
DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_host_x86=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art:/system/framework/x86/boot-framework.art out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat:/system/framework/x86/boot-framework.oat
DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_host_x86_64=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art:/system/framework/x86_64/boot-framework.art out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat:/system/framework/x86_64/boot-framework.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_mainline_arm=out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.art:/system/framework/arm/boot-framework-foo.art out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.oat:/system/framework/arm/boot-framework-foo.oat out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-bar.art:/system/framework/arm/boot-framework-bar.art out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-bar.oat:/system/framework/arm/boot-framework-bar.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_mainline_arm64=out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art:/system/framework/arm64/boot-framework-foo.art out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.oat:/system/framework/arm64/boot-framework-foo.oat out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-bar.art:/system/framework/arm64/boot-framework-bar.art out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-bar.oat:/system/framework/arm64/boot-framework-bar.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_mainline_host_x86=out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art:/system/framework/x86/boot-framework-foo.art out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.oat:/system/framework/x86/boot-framework-foo.oat out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-bar.art:/system/framework/x86/boot-framework-bar.art out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-bar.oat:/system/framework/x86/boot-framework-bar.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_mainline_host_x86_64=out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art:/system/framework/x86_64/boot-framework-foo.art out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.oat:/system/framework/x86_64/boot-framework-foo.oat out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-bar.art:/system/framework/x86_64/boot-framework-bar.art out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-bar.oat:/system/framework/x86_64/boot-framework-bar.oat
DEXPREOPT_IMAGE_DEPS_art_arm=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex
DEXPREOPT_IMAGE_DEPS_art_arm64=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex
DEXPREOPT_IMAGE_DEPS_art_host_x86=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex
@@ -720,6 +1156,10 @@ DEXPREOPT_IMAGE_DEPS_boot_arm=out/soong/test_device/dex_bootjars/android/system/
DEXPREOPT_IMAGE_DEPS_boot_arm64=out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.oat out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.vdex
DEXPREOPT_IMAGE_DEPS_boot_host_x86=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex
DEXPREOPT_IMAGE_DEPS_boot_host_x86_64=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex
+DEXPREOPT_IMAGE_DEPS_mainline_arm=out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.art out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.oat out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.vdex out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-bar.art out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-bar.oat out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-bar.vdex
+DEXPREOPT_IMAGE_DEPS_mainline_arm64=out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.oat out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.vdex out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-bar.art out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-bar.oat out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-bar.vdex
+DEXPREOPT_IMAGE_DEPS_mainline_host_x86=out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.oat out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.vdex out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-bar.art out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-bar.oat out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-bar.vdex
+DEXPREOPT_IMAGE_DEPS_mainline_host_x86_64=out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.oat out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.vdex out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-bar.art out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-bar.oat out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-bar.vdex
DEXPREOPT_IMAGE_LICENSE_METADATA_art_arm=%[1]s
DEXPREOPT_IMAGE_LICENSE_METADATA_art_arm64=%[1]s
DEXPREOPT_IMAGE_LICENSE_METADATA_art_host_x86=%[1]s
@@ -728,11 +1168,17 @@ DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm=out/soong/.intermediates/frameworks/ba
DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86_64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_arm=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_arm64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_host_x86=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_host_x86_64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEart=/system/framework/boot.art
DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEboot=/system/framework/boot.art:/system/framework/boot-framework.art
+DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEmainline=/system/framework/boot.art:/system/framework/boot-framework.art:/system/framework/boot-framework-foo.art
DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTart=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/boot.art
DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTboot=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/boot.art:out/soong/test_device/dex_bootjars/android/system/framework/boot-framework.art
-DEXPREOPT_IMAGE_NAMES=art boot
+DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTmainline=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/boot.art:out/soong/test_device/dex_bootjars/android/system/framework/boot-framework.art:out/soong/test_device/dex_mainlinejars/android/system/framework/boot-framework-foo.art
+DEXPREOPT_IMAGE_NAMES=art boot mainline
DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED=out/soong/test_device/dex_bootjars/boot.bprof:/system/etc/boot-image.bprof out/soong/test_device/dex_bootjars/boot.prof:/system/etc/boot-image.prof
DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm=out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat
@@ -743,6 +1189,10 @@ DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_arm=out/soong/test_device/dex_bo
DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_arm64=out/soong/test_device/dex_bootjars_unstripped/android/system/framework/arm64/boot-framework.oat:/system/framework/arm64/boot-framework.oat
DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_host_x86=out/soong/test_device/dex_bootjars_unstripped/linux_glibc/system/framework/x86/boot-framework.oat:/system/framework/x86/boot-framework.oat
DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_host_x86_64=out/soong/test_device/dex_bootjars_unstripped/linux_glibc/system/framework/x86_64/boot-framework.oat:/system/framework/x86_64/boot-framework.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_mainline_arm=out/soong/test_device/dex_mainlinejars_unstripped/android/system/framework/arm/boot-framework-foo.oat:/system/framework/arm/boot-framework-foo.oat out/soong/test_device/dex_mainlinejars_unstripped/android/system/framework/arm/boot-framework-bar.oat:/system/framework/arm/boot-framework-bar.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_mainline_arm64=out/soong/test_device/dex_mainlinejars_unstripped/android/system/framework/arm64/boot-framework-foo.oat:/system/framework/arm64/boot-framework-foo.oat out/soong/test_device/dex_mainlinejars_unstripped/android/system/framework/arm64/boot-framework-bar.oat:/system/framework/arm64/boot-framework-bar.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_mainline_host_x86=out/soong/test_device/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86/boot-framework-foo.oat:/system/framework/x86/boot-framework-foo.oat out/soong/test_device/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86/boot-framework-bar.oat:/system/framework/x86/boot-framework-bar.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_mainline_host_x86_64=out/soong/test_device/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86_64/boot-framework-foo.oat:/system/framework/x86_64/boot-framework-foo.oat out/soong/test_device/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86_64/boot-framework-bar.oat:/system/framework/x86_64/boot-framework-bar.oat
DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_arm=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex:/apex/art_boot_images/javalib/arm/boot.vdex out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex:/apex/art_boot_images/javalib/arm/boot-core2.vdex
DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_arm64=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex:/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex:/apex/art_boot_images/javalib/arm64/boot-core2.vdex
DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_host_x86=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex:/apex/art_boot_images/javalib/x86/boot.vdex out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex:/apex/art_boot_images/javalib/x86/boot-core2.vdex
@@ -751,8 +1201,13 @@ DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_arm=out/soong/test_device/dex_bootjars
DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_arm64=out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.vdex:/system/framework/arm64/boot-framework.vdex
DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_host_x86=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex:/system/framework/x86/boot-framework.vdex
DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_host_x86_64=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex:/system/framework/x86_64/boot-framework.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_mainline_arm=out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.vdex:/system/framework/arm/boot-framework-foo.vdex out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-bar.vdex:/system/framework/arm/boot-framework-bar.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_mainline_arm64=out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.vdex:/system/framework/arm64/boot-framework-foo.vdex out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-bar.vdex:/system/framework/arm64/boot-framework-bar.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_mainline_host_x86=out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.vdex:/system/framework/x86/boot-framework-foo.vdex out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-bar.vdex:/system/framework/x86/boot-framework-bar.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_mainline_host_x86_64=out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.vdex:/system/framework/x86_64/boot-framework-foo.vdex out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-bar.vdex:/system/framework/x86_64/boot-framework-bar.vdex
DEXPREOPT_IMAGE_ZIP_art=out/soong/test_device/dex_artjars/art.zip
DEXPREOPT_IMAGE_ZIP_boot=out/soong/test_device/dex_bootjars/boot.zip
+DEXPREOPT_IMAGE_ZIP_mainline=out/soong/test_device/dex_mainlinejars/mainline.zip
DEXPREOPT_IMAGE_art_arm=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art
DEXPREOPT_IMAGE_art_arm64=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art
DEXPREOPT_IMAGE_art_host_x86=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art
@@ -761,6 +1216,10 @@ DEXPREOPT_IMAGE_boot_arm=out/soong/test_device/dex_bootjars/android/system/frame
DEXPREOPT_IMAGE_boot_arm64=out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art
DEXPREOPT_IMAGE_boot_host_x86=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art
DEXPREOPT_IMAGE_boot_host_x86_64=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art
+DEXPREOPT_IMAGE_mainline_arm=out/soong/test_device/dex_mainlinejars/android/system/framework/arm/boot-framework-foo.art
+DEXPREOPT_IMAGE_mainline_arm64=out/soong/test_device/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art
+DEXPREOPT_IMAGE_mainline_host_x86=out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art
+DEXPREOPT_IMAGE_mainline_host_x86_64=out/soong/test_device/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art
`
expected := strings.TrimSpace(fmt.Sprintf(format, expectedLicenseMetadataFile))
actual := strings.TrimSpace(out.String())
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 01a2c1435..e98b9ea29 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -603,12 +603,10 @@ func (d *Droiddoc) doclavaDocsFlags(ctx android.ModuleContext, cmd *android.Rule
Flag("-J-XX:-OmitStackTraceInFastThrow").
Flag("-XDignore.symbol.file").
Flag("--ignore-source-errors").
- // b/240421555: use a stub doclet until Doclava works with JDK 17
- //FlagWithArg("-doclet ", "com.google.doclava.Doclava").
- FlagWithArg("-doclet ", "com.google.stubdoclet.StubDoclet").
+ FlagWithArg("-doclet ", "com.google.doclava.Doclava").
FlagWithInputList("-docletpath ", docletPath.Paths(), ":").
- FlagWithArg("-Xmaxerrs ", "1").
- FlagWithArg("-Xmaxwarns ", "1").
+ FlagWithArg("-Xmaxerrs ", "10").
+ FlagWithArg("-Xmaxwarns ", "10").
Flag("-J--add-exports=jdk.javadoc/jdk.javadoc.internal.doclets.formats.html=ALL-UNNAMED").
Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED").
FlagWithArg("-hdf page.build ", ctx.Config().BuildId()+"-$(cat "+buildNumberFile.String()+")").OrderOnly(buildNumberFile).
@@ -780,8 +778,6 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
jsilver := ctx.Config().HostJavaToolPath(ctx, "jsilver.jar")
doclava := ctx.Config().HostJavaToolPath(ctx, "doclava.jar")
- // b/240421555: use a stub doclet until Doclava works with JDK 17
- stubdoclet := ctx.Config().HostJavaToolPath(ctx, "stubdoclet.jar")
outDir := android.PathForModuleOut(ctx, "out")
srcJarDir := android.PathForModuleOut(ctx, "srcjars")
@@ -809,8 +805,7 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if Bool(d.properties.Dokka_enabled) {
desc = "dokka"
} else {
- // b/240421555: use a stub doclet until Doclava works with JDK 17
- d.doclavaDocsFlags(ctx, cmd, classpath{jsilver, doclava, stubdoclet})
+ d.doclavaDocsFlags(ctx, cmd, classpath{jsilver, doclava})
for _, o := range d.Javadoc.properties.Out {
cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
@@ -828,9 +823,9 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
FlagWithArg("-C ", outDir.String()).
FlagWithArg("-D ", outDir.String())
- // rule.Restat()
+ rule.Restat()
- // zipSyncCleanupCmd(rule, srcJarDir)
+ zipSyncCleanupCmd(rule, srcJarDir)
rule.Build("javadoc", desc)
}
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index cf9c7ad7a..c4fc65f2e 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -20,10 +20,17 @@ import (
"android/soong/android"
)
-var hiddenAPIGenerateCSVRule = pctx.AndroidStaticRule("hiddenAPIGenerateCSV", blueprint.RuleParams{
- Command: "${config.Class2NonSdkList} --stub-api-flags ${stubAPIFlags} $in $outFlag $out",
- CommandDeps: []string{"${config.Class2NonSdkList}"},
-}, "outFlag", "stubAPIFlags")
+var (
+ hiddenAPIGenerateCSVRule = pctx.AndroidStaticRule("hiddenAPIGenerateCSV", blueprint.RuleParams{
+ Command: "${config.Class2NonSdkList} --stub-api-flags ${stubAPIFlags} $in $outFlag $out",
+ CommandDeps: []string{"${config.Class2NonSdkList}"},
+ }, "outFlag", "stubAPIFlags")
+
+ hiddenAPIGenerateIndexRule = pctx.AndroidStaticRule("hiddenAPIGenerateIndex", blueprint.RuleParams{
+ Command: "${config.MergeCsvCommand} --zip_input --key_field signature --output=$out $in",
+ CommandDeps: []string{"${config.MergeCsvCommand}"},
+ })
+)
type hiddenAPI struct {
// True if the module containing this structure contributes to the hiddenapi information or has
@@ -216,14 +223,12 @@ func buildRuleToGenerateMetadata(ctx android.ModuleContext, desc string, classes
// created by the unsupported app usage annotation processor during compilation of the class
// implementation jar.
func buildRuleToGenerateIndex(ctx android.ModuleContext, desc string, classesJars android.Paths, indexCSV android.WritablePath) {
- rule := android.NewRuleBuilder(pctx, ctx)
- rule.Command().
- BuiltTool("merge_csv").
- Flag("--zip_input").
- Flag("--key_field signature").
- FlagWithOutput("--output=", indexCSV).
- Inputs(classesJars)
- rule.Build(desc, desc)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: hiddenAPIGenerateIndexRule,
+ Description: desc,
+ Inputs: classesJars,
+ Output: indexCSV,
+ })
}
var hiddenAPIEncodeDexRule = pctx.AndroidStaticRule("hiddenAPIEncodeDex", blueprint.RuleParams{
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 593d7724f..be4a48e5b 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -697,7 +697,7 @@ func (s StubDexJarsByModule) addStubDexJarsByModule(other StubDexJarsByModule) {
// The relative width of APIs is determined by their order in hiddenAPIScopes.
func (s StubDexJarsByModule) StubDexJarsForWidestAPIScope() android.Paths {
stubDexJars := android.Paths{}
- modules := android.SortedStringKeys(s)
+ modules := android.SortedKeys(s)
for _, module := range modules {
stubDexJarsByScope := s[module]
@@ -714,7 +714,7 @@ func (s StubDexJarsByModule) StubDexJarsForWidestAPIScope() android.Paths {
// the returned list.
func (s StubDexJarsByModule) StubDexJarsForScope(scope *HiddenAPIScope) android.Paths {
stubDexJars := android.Paths{}
- modules := android.SortedStringKeys(s)
+ modules := android.SortedKeys(s)
for _, module := range modules {
stubDexJarsByScope := s[module]
// Not every module will have the same set of
@@ -917,7 +917,7 @@ func (b bootDexJarByModule) addPath(module android.Module, path android.Path) {
// bootDexJars returns the boot dex jar paths sorted by their keys.
func (b bootDexJarByModule) bootDexJars() android.Paths {
paths := android.Paths{}
- for _, k := range android.SortedStringKeys(b) {
+ for _, k := range android.SortedKeys(b) {
paths = append(paths, b[k])
}
return paths
@@ -927,7 +927,7 @@ func (b bootDexJarByModule) bootDexJars() android.Paths {
// libraries if present.
func (b bootDexJarByModule) bootDexJarsWithoutCoverage() android.Paths {
paths := android.Paths{}
- for _, k := range android.SortedStringKeys(b) {
+ for _, k := range android.SortedKeys(b) {
if k == "jacocoagent" {
continue
}
@@ -1217,7 +1217,7 @@ func hiddenAPIEncodeRulesForBootclasspathFragment(ctx android.ModuleContext, boo
// Encode the flags into the boot dex files.
encodedBootDexJarsByModule := bootDexJarByModule{}
outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath
- for _, name := range android.SortedStringKeys(bootDexInfoByModule) {
+ for _, name := range android.SortedKeys(bootDexInfoByModule) {
bootDexInfo := bootDexInfoByModule[name]
unencodedDex := bootDexInfo.path
encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, allFlagsCSV, bootDexInfo.uncompressDex, bootDexInfo.minSdkVersion, outputDir)
@@ -1288,7 +1288,7 @@ type bootDexInfoByModule map[string]bootDexInfo
// bootDexJars returns the boot dex jar paths sorted by their keys.
func (b bootDexInfoByModule) bootDexJars() android.Paths {
paths := android.Paths{}
- for _, m := range android.SortedStringKeys(b) {
+ for _, m := range android.SortedKeys(b) {
paths = append(paths, b[m].path)
}
return paths
diff --git a/java/java.go b/java/java.go
index 659f98a7c..a00e26f83 100644
--- a/java/java.go
+++ b/java/java.go
@@ -517,14 +517,8 @@ func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext an
return normalizeJavaVersion(ctx, javaVersion)
} else if ctx.Device() {
return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion(ctx))
- } else if ctx.Config().TargetsJava17() {
- // Temporary experimental flag to be able to try and build with
- // java version 17 options. The flag, if used, just sets Java
- // 17 as the default version, leaving any components that
- // target an older version intact.
- return JAVA_VERSION_17
} else {
- return JAVA_VERSION_11
+ return JAVA_VERSION_17
}
}
@@ -801,6 +795,8 @@ type librarySdkMemberProperties struct {
// The value of the min_sdk_version property, translated into a number where possible.
MinSdkVersion *string `supported_build_releases:"Tiramisu+"`
+
+ DexPreoptProfileGuided *bool `supported_build_releases:"UpsideDownCake+"`
}
func (p *librarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
@@ -818,6 +814,10 @@ func (p *librarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberCo
canonical := android.ReplaceFinalizedCodenames(ctx.SdkModuleContext().Config(), j.minSdkVersion.ApiLevel.String())
p.MinSdkVersion = proptools.StringPtr(canonical)
}
+
+ if j.dexpreopter.dexpreoptProperties.Dex_preopt_result.Profile_guided {
+ p.DexPreoptProfileGuided = proptools.BoolPtr(true)
+ }
}
func (p *librarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
@@ -844,6 +844,11 @@ func (p *librarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberConte
propertySet.AddProperty("permitted_packages", p.PermittedPackages)
}
+ dexPreoptSet := propertySet.AddPropertySet("dex_preopt")
+ if p.DexPreoptProfileGuided != nil {
+ dexPreoptSet.AddProperty("profile_guided", proptools.Bool(p.DexPreoptProfileGuided))
+ }
+
// Do not copy anything else to the snapshot.
if memberType.onlyCopyJarToSnapshot {
return
@@ -1633,6 +1638,10 @@ type JavaApiLibraryProperties struct {
// List of shared java libs that this module has dependencies to and
// should be passed as classpath in javac invocation
Libs []string
+
+ // List of java libs that this module has static dependencies to and will be
+ // passed in metalava invocation
+ Static_libs []string
}
func ApiLibraryFactory() android.Module {
@@ -1705,6 +1714,7 @@ func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
ctx.AddDependency(ctx.Module(), javaApiContributionTag, apiContributionName)
}
ctx.AddVariationDependencies(nil, libTag, al.properties.Libs...)
+ ctx.AddVariationDependencies(nil, staticLibTag, al.properties.Static_libs...)
}
func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -1724,6 +1734,7 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
var srcFiles android.Paths
var classPaths android.Paths
+ var staticLibs android.Paths
ctx.VisitDirectDeps(func(dep android.Module) {
tag := ctx.OtherModuleDependencyTag(dep)
switch tag {
@@ -1737,6 +1748,9 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
case libTag:
provider := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
classPaths = append(classPaths, provider.HeaderJars...)
+ case staticLibTag:
+ provider := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+ staticLibs = append(staticLibs, provider.HeaderJars...)
}
})
@@ -1761,17 +1775,25 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
FlagWithArg("-D ", stubsDir.String())
rule.Build("metalava", "metalava merged")
-
- al.stubsJar = android.PathForModuleOut(ctx, ctx.ModuleName(), "android.jar")
+ compiledStubs := android.PathForModuleOut(ctx, ctx.ModuleName(), "stubs.jar")
+ al.stubsJar = android.PathForModuleOut(ctx, ctx.ModuleName(), fmt.Sprintf("%s.jar", ctx.ModuleName()))
var flags javaBuilderFlags
flags.javaVersion = getStubsJavaVersion()
flags.javacFlags = strings.Join(al.properties.Javacflags, " ")
flags.classpath = classpath(classPaths)
- TransformJavaToClasses(ctx, al.stubsJar, 0, android.Paths{},
+ TransformJavaToClasses(ctx, compiledStubs, 0, android.Paths{},
android.Paths{al.stubsSrcJar}, flags, android.Paths{})
+ builder := android.NewRuleBuilder(pctx, ctx)
+ builder.Command().
+ BuiltTool("merge_zips").
+ Output(al.stubsJar).
+ Inputs(android.Paths{compiledStubs}).
+ Inputs(staticLibs)
+ builder.Build("merge_zips", "merge jar files")
+
ctx.Phony(ctx.ModuleName(), al.stubsJar)
ctx.SetProvider(JavaInfoProvider, JavaInfo{
@@ -1997,7 +2019,8 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if di == nil {
return // An error has been reported by FindDeapexerProviderForModule.
}
- if dexOutputPath := di.PrebuiltExportPath(apexRootRelativePathToJavaLib(j.BaseModuleName())); dexOutputPath != nil {
+ dexJarFileApexRootRelative := apexRootRelativePathToJavaLib(j.BaseModuleName())
+ if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil {
dexJarFile := makeDexJarPathFromPath(dexOutputPath)
j.dexJarFile = dexJarFile
installPath := android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, apexRootRelativePathToJavaLib(j.BaseModuleName()))
@@ -2006,6 +2029,11 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.dexpreopter.installPath = j.dexpreopter.getInstallPath(ctx, installPath)
setUncompressDex(ctx, &j.dexpreopter, &j.dexer)
j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
+
+ if profilePath := di.PrebuiltExportPath(dexJarFileApexRootRelative + ".prof"); profilePath != nil {
+ j.dexpreopter.inputProfilePathOnHost = profilePath
+ }
+
j.dexpreopt(ctx, dexOutputPath)
// Initialize the hiddenapi structure.
@@ -2033,7 +2061,15 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
var dexOutputFile android.OutputPath
- dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(ctx), outputFile, jarName)
+ dexParams := &compileDexParams{
+ flags: flags,
+ sdkVersion: j.SdkVersion(ctx),
+ minSdkVersion: j.MinSdkVersion(ctx),
+ classesJar: outputFile,
+ jarName: jarName,
+ }
+
+ dexOutputFile = j.dexer.compileDex(ctx, dexParams)
if ctx.Failed() {
return
}
@@ -2124,15 +2160,18 @@ func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu
// Implements android.ApexModule
func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
sdkVersion android.ApiLevel) error {
- sdkSpec := j.MinSdkVersion(ctx)
- if !sdkSpec.Specified() {
+ sdkVersionSpec := j.SdkVersion(ctx)
+ minSdkVersionSpec := j.MinSdkVersion(ctx)
+ if !minSdkVersionSpec.Specified() {
return fmt.Errorf("min_sdk_version is not specified")
}
- if sdkSpec.Kind == android.SdkCore {
+ // If the module is compiling against core (via sdk_version), skip comparison check.
+ if sdkVersionSpec.Kind == android.SdkCore {
return nil
}
- if sdkSpec.ApiLevel.GreaterThan(sdkVersion) {
- return fmt.Errorf("newer SDK(%v)", sdkSpec.ApiLevel)
+ minSdkVersion := minSdkVersionSpec.ApiLevel
+ if minSdkVersion.GreaterThan(sdkVersion) {
+ return fmt.Errorf("newer SDK(%v)", minSdkVersion)
}
return nil
}
@@ -2140,11 +2179,16 @@ func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
// requiredFilesFromPrebuiltApexForImport returns information about the files that a java_import or
// java_sdk_library_import with the specified base module name requires to be exported from a
// prebuilt_apex/apex_set.
-func requiredFilesFromPrebuiltApexForImport(name string) []string {
+func requiredFilesFromPrebuiltApexForImport(name string, d *dexpreopter) []string {
+ dexJarFileApexRootRelative := apexRootRelativePathToJavaLib(name)
// Add the dex implementation jar to the set of exported files.
- return []string{
- apexRootRelativePathToJavaLib(name),
+ files := []string{
+ dexJarFileApexRootRelative,
+ }
+ if BoolDefault(d.importDexpreoptProperties.Dex_preopt.Profile_guided, false) {
+ files = append(files, dexJarFileApexRootRelative+".prof")
}
+ return files
}
// apexRootRelativePathToJavaLib returns the path, relative to the root of the apex's contents, for
@@ -2157,7 +2201,7 @@ var _ android.RequiredFilesFromPrebuiltApex = (*Import)(nil)
func (j *Import) RequiredFilesFromPrebuiltApex(_ android.BaseModuleContext) []string {
name := j.BaseModuleName()
- return requiredFilesFromPrebuiltApexForImport(name)
+ return requiredFilesFromPrebuiltApexForImport(name, &j.dexpreopter)
}
// Add compile time check for interface implementation
@@ -2198,6 +2242,7 @@ func ImportFactory() android.Module {
module.AddProperties(
&module.properties,
&module.dexer.dexProperties,
+ &module.importDexpreoptProperties,
)
module.initModuleAndImport(module)
@@ -2767,6 +2812,9 @@ func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) {
if sdkVersion.Kind == android.SdkPublic && sdkVersion.ApiLevel == android.FutureApiLevel {
// TODO(b/220869005) remove forced dependency on current public android.jar
deps.Add(bazel.MakeLabelAttribute("//prebuilts/sdk:public_current_android_sdk_java_import"))
+ } else if sdkVersion.Kind == android.SdkSystem && sdkVersion.ApiLevel == android.FutureApiLevel {
+ // TODO(b/215230098) remove forced dependency on current public android.jar
+ deps.Add(bazel.MakeLabelAttribute("//prebuilts/sdk:system_current_android_sdk_java_import"))
}
} else if !deps.IsEmpty() {
ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.")
diff --git a/java/java_test.go b/java/java_test.go
index 21993eccf..05cc23e29 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -2037,11 +2037,11 @@ func TestJavaApiLibraryJarGeneration(t *testing.T) {
}{
{
moduleName: "bar1",
- outputJarName: "bar1/android.jar",
+ outputJarName: "bar1/bar1.jar",
},
{
moduleName: "bar2",
- outputJarName: "bar2/android.jar",
+ outputJarName: "bar2/bar2.jar",
},
}
for _, c := range testcases {
@@ -2113,7 +2113,7 @@ func TestJavaApiLibraryLibsLink(t *testing.T) {
},
{
moduleName: "bar2",
- classPathJarNames: []string{"lib1.jar", "lib2.jar", "bar1/android.jar"},
+ classPathJarNames: []string{"lib1.jar", "lib2.jar", "bar1/bar1.jar"},
},
}
for _, c := range testcases {
@@ -2128,6 +2128,80 @@ func TestJavaApiLibraryLibsLink(t *testing.T) {
}
}
+func TestJavaApiLibraryStaticLibsLink(t *testing.T) {
+ provider_bp_a := `
+ java_api_contribution {
+ name: "foo1",
+ api_file: "foo1.txt",
+ }
+ `
+ provider_bp_b := `
+ java_api_contribution {
+ name: "foo2",
+ api_file: "foo2.txt",
+ }
+ `
+ lib_bp_a := `
+ java_library {
+ name: "lib1",
+ srcs: ["Lib.java"],
+ }
+ `
+ lib_bp_b := `
+ java_library {
+ name: "lib2",
+ srcs: ["Lib.java"],
+ }
+ `
+
+ ctx, _ := testJavaWithFS(t, `
+ java_api_library {
+ name: "bar1",
+ api_surface: "public",
+ api_contributions: ["foo1"],
+ static_libs: ["lib1"],
+ }
+
+ java_api_library {
+ name: "bar2",
+ api_surface: "system",
+ api_contributions: ["foo1", "foo2"],
+ static_libs: ["lib1", "lib2", "bar1"],
+ }
+ `,
+ map[string][]byte{
+ "a/Android.bp": []byte(provider_bp_a),
+ "b/Android.bp": []byte(provider_bp_b),
+ "c/Android.bp": []byte(lib_bp_a),
+ "c/Lib.java": {},
+ "d/Android.bp": []byte(lib_bp_b),
+ "d/Lib.java": {},
+ })
+
+ testcases := []struct {
+ moduleName string
+ staticLibJarNames []string
+ }{
+ {
+ moduleName: "bar1",
+ staticLibJarNames: []string{"lib1.jar"},
+ },
+ {
+ moduleName: "bar2",
+ staticLibJarNames: []string{"lib1.jar", "lib2.jar", "bar1/bar1.jar"},
+ },
+ }
+ for _, c := range testcases {
+ m := ctx.ModuleForTests(c.moduleName, "android_common")
+ mergeZipsCommand := m.Rule("merge_zips").RuleParams.Command
+ for _, jarName := range c.staticLibJarNames {
+ if !strings.Contains(mergeZipsCommand, jarName) {
+ t.Errorf("merge_zips command does not contain expected jar %s", jarName)
+ }
+ }
+ }
+}
+
func TestTradefedOptions(t *testing.T) {
result := PrepareForTestWithJavaBuildComponents.RunTestWithBp(t, `
java_test_host {
diff --git a/java/lint.go b/java/lint.go
index 07b962912..a457d4475 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -159,6 +159,50 @@ func (l LintDepSetsBuilder) Build() LintDepSets {
}
}
+type lintDatabaseFiles struct {
+ apiVersionsModule string
+ apiVersionsCopiedName string
+ apiVersionsPrebuiltPath string
+ annotationsModule string
+ annotationCopiedName string
+ annotationPrebuiltpath string
+}
+
+var allLintDatabasefiles = map[android.SdkKind]lintDatabaseFiles{
+ android.SdkPublic: {
+ apiVersionsModule: "api_versions_public",
+ apiVersionsCopiedName: "api_versions_public.xml",
+ apiVersionsPrebuiltPath: "prebuilts/sdk/current/public/data/api-versions.xml",
+ annotationsModule: "sdk-annotations.zip",
+ annotationCopiedName: "annotations-public.zip",
+ annotationPrebuiltpath: "prebuilts/sdk/current/public/data/annotations.zip",
+ },
+ android.SdkSystem: {
+ apiVersionsModule: "api_versions_system",
+ apiVersionsCopiedName: "api_versions_system.xml",
+ apiVersionsPrebuiltPath: "prebuilts/sdk/current/system/data/api-versions.xml",
+ annotationsModule: "sdk-annotations-system.zip",
+ annotationCopiedName: "annotations-system.zip",
+ annotationPrebuiltpath: "prebuilts/sdk/current/system/data/annotations.zip",
+ },
+ android.SdkModule: {
+ apiVersionsModule: "api_versions_module_lib",
+ apiVersionsCopiedName: "api_versions_module_lib.xml",
+ apiVersionsPrebuiltPath: "prebuilts/sdk/current/module-lib/data/api-versions.xml",
+ annotationsModule: "sdk-annotations-module-lib.zip",
+ annotationCopiedName: "annotations-module-lib.zip",
+ annotationPrebuiltpath: "prebuilts/sdk/current/module-lib/data/annotations.zip",
+ },
+ android.SdkSystemServer: {
+ apiVersionsModule: "api_versions_system_server",
+ apiVersionsCopiedName: "api_versions_system_server.xml",
+ apiVersionsPrebuiltPath: "prebuilts/sdk/current/system-server/data/api-versions.xml",
+ annotationsModule: "sdk-annotations-system-server.zip",
+ annotationCopiedName: "annotations-system-server.zip",
+ annotationPrebuiltpath: "prebuilts/sdk/current/system-server/data/annotations.zip",
+ },
+}
+
func (l *linter) LintDepSets() LintDepSets {
return l.outputs.depSets
}
@@ -269,19 +313,25 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.Ru
cmd.FlagWithInput("@",
android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
- cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
+ if l.compileSdkKind == android.SdkPublic {
+ cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
+ } else {
+ // TODO(b/268261262): Remove this branch. We're demoting NewApi to a warning due to pre-existing issues that need to be fixed.
+ cmd.FlagForEachArg("--warning_check ", l.extraMainlineLintErrors)
+ }
cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
- if l.GetStrictUpdatabilityLinting() {
- // Verify the module does not baseline issues that endanger safe updatability.
- if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
- cmd.FlagWithInput("--baseline ", baselinePath.Path())
- cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
- }
- }
+ // TODO(b/193460475): Re-enable strict updatability linting
+ //if l.GetStrictUpdatabilityLinting() {
+ // // Verify the module does not baseline issues that endanger safe updatability.
+ // if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
+ // cmd.FlagWithInput("--baseline ", baselinePath.Path())
+ // cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
+ // }
+ //}
return lintPaths{
projectXML: projectXMLPath,
@@ -414,26 +464,17 @@ func (l *linter) lint(ctx android.ModuleContext) {
rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
- var apiVersionsName, apiVersionsPrebuilt string
- if l.compileSdkKind == android.SdkModule || l.compileSdkKind == android.SdkSystemServer {
- // When compiling an SDK module (or system server) we use the filtered
- // database because otherwise lint's
- // NewApi check produces too many false positives; This database excludes information
- // about classes created in mainline modules hence removing those false positives.
- apiVersionsName = "api_versions_public_filtered.xml"
- apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions-filtered.xml"
- } else {
- apiVersionsName = "api_versions.xml"
- apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions.xml"
+ files, ok := allLintDatabasefiles[l.compileSdkKind]
+ if !ok {
+ files = allLintDatabasefiles[android.SdkPublic]
}
-
var annotationsZipPath, apiVersionsXMLPath android.Path
if ctx.Config().AlwaysUsePrebuiltSdks() {
- annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
- apiVersionsXMLPath = android.PathForSource(ctx, apiVersionsPrebuilt)
+ annotationsZipPath = android.PathForSource(ctx, files.annotationPrebuiltpath)
+ apiVersionsXMLPath = android.PathForSource(ctx, files.apiVersionsPrebuiltPath)
} else {
- annotationsZipPath = copiedAnnotationsZipPath(ctx)
- apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx, apiVersionsName)
+ annotationsZipPath = copiedLintDatabaseFilesPath(ctx, files.annotationCopiedName)
+ apiVersionsXMLPath = copiedLintDatabaseFilesPath(ctx, files.apiVersionsCopiedName)
}
cmd := rule.Command()
@@ -558,54 +599,39 @@ func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
return
}
- apiVersionsDb := findModuleOrErr(ctx, "api_versions_public")
- if apiVersionsDb == nil {
- if !ctx.Config().AllowMissingDependencies() {
- ctx.Errorf("lint: missing module api_versions_public")
+ for _, sdk := range android.SortedKeys(allLintDatabasefiles) {
+ files := allLintDatabasefiles[sdk]
+ apiVersionsDb := findModuleOrErr(ctx, files.apiVersionsModule)
+ if apiVersionsDb == nil {
+ if !ctx.Config().AllowMissingDependencies() {
+ ctx.Errorf("lint: missing module api_versions_public")
+ }
+ return
}
- return
- }
- sdkAnnotations := findModuleOrErr(ctx, "sdk-annotations.zip")
- if sdkAnnotations == nil {
- if !ctx.Config().AllowMissingDependencies() {
- ctx.Errorf("lint: missing module sdk-annotations.zip")
- }
- return
- }
-
- filteredDb := findModuleOrErr(ctx, "api-versions-xml-public-filtered")
- if filteredDb == nil {
- if !ctx.Config().AllowMissingDependencies() {
- ctx.Errorf("lint: missing api-versions-xml-public-filtered")
+ sdkAnnotations := findModuleOrErr(ctx, files.annotationsModule)
+ if sdkAnnotations == nil {
+ if !ctx.Config().AllowMissingDependencies() {
+ ctx.Errorf("lint: missing module sdk-annotations.zip")
+ }
+ return
}
- return
- }
-
- ctx.Build(pctx, android.BuildParams{
- Rule: android.CpIfChanged,
- Input: android.OutputFileForModule(ctx, sdkAnnotations, ""),
- Output: copiedAnnotationsZipPath(ctx),
- })
- ctx.Build(pctx, android.BuildParams{
- Rule: android.CpIfChanged,
- Input: android.OutputFileForModule(ctx, apiVersionsDb, ".api_versions.xml"),
- Output: copiedAPIVersionsXmlPath(ctx, "api_versions.xml"),
- })
-
- ctx.Build(pctx, android.BuildParams{
- Rule: android.CpIfChanged,
- Input: android.OutputFileForModule(ctx, filteredDb, ""),
- Output: copiedAPIVersionsXmlPath(ctx, "api_versions_public_filtered.xml"),
- })
-}
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.CpIfChanged,
+ Input: android.OutputFileForModule(ctx, sdkAnnotations, ""),
+ Output: copiedLintDatabaseFilesPath(ctx, files.annotationCopiedName),
+ })
-func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
- return android.PathForOutput(ctx, "lint", "annotations.zip")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.CpIfChanged,
+ Input: android.OutputFileForModule(ctx, apiVersionsDb, ".api_versions.xml"),
+ Output: copiedLintDatabaseFilesPath(ctx, files.apiVersionsCopiedName),
+ })
+ }
}
-func copiedAPIVersionsXmlPath(ctx android.PathContext, name string) android.WritablePath {
+func copiedLintDatabaseFilesPath(ctx android.PathContext, name string) android.WritablePath {
return android.PathForOutput(ctx, "lint", name)
}
diff --git a/java/lint_test.go b/java/lint_test.go
index 62450d573..ec901aa70 100644
--- a/java/lint_test.go
+++ b/java/lint_test.go
@@ -113,8 +113,9 @@ func TestJavaLintUsesCorrectBpConfig(t *testing.T) {
t.Error("did not use the correct file for baseline")
}
- if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check NewApi") {
- t.Error("should check NewApi errors")
+ if !strings.Contains(*sboxProto.Commands[0].Command, "--warning_check NewApi") {
+ // TODO(b/268261262): Change this to check for --error_check
+ t.Error("should check NewApi warnings")
}
if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check SomeCheck") {
@@ -174,55 +175,83 @@ func TestJavaLintBypassUpdatableChecks(t *testing.T) {
}
}
-func TestJavaLintStrictUpdatabilityLinting(t *testing.T) {
- bp := `
- java_library {
- name: "foo",
- srcs: [
- "a.java",
- ],
- static_libs: ["bar"],
- min_sdk_version: "29",
- sdk_version: "current",
- lint: {
- strict_updatability_linting: true,
- },
- }
-
- java_library {
- name: "bar",
- srcs: [
- "a.java",
- ],
- min_sdk_version: "29",
- sdk_version: "current",
- }
- `
- fs := android.MockFS{
- "lint-baseline.xml": nil,
- }
-
- result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules, fs.AddToFixture()).
- RunTestWithBp(t, bp)
-
- foo := result.ModuleForTests("foo", "android_common")
- sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
- if !strings.Contains(*sboxProto.Commands[0].Command,
- "--baseline lint-baseline.xml --disallowed_issues NewApi") {
- t.Error("did not restrict baselining NewApi")
- }
-
- bar := result.ModuleForTests("bar", "android_common")
- sboxProto = android.RuleBuilderSboxProtoForTests(t, bar.Output("lint.sbox.textproto"))
- if !strings.Contains(*sboxProto.Commands[0].Command,
- "--baseline lint-baseline.xml --disallowed_issues NewApi") {
- t.Error("did not restrict baselining NewApi")
- }
-}
+// TODO(b/193460475): Re-enable this test
+//func TestJavaLintStrictUpdatabilityLinting(t *testing.T) {
+// bp := `
+// java_library {
+// name: "foo",
+// srcs: [
+// "a.java",
+// ],
+// static_libs: ["bar"],
+// min_sdk_version: "29",
+// sdk_version: "current",
+// lint: {
+// strict_updatability_linting: true,
+// },
+// }
+//
+// java_library {
+// name: "bar",
+// srcs: [
+// "a.java",
+// ],
+// min_sdk_version: "29",
+// sdk_version: "current",
+// }
+// `
+// fs := android.MockFS{
+// "lint-baseline.xml": nil,
+// }
+//
+// result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules, fs.AddToFixture()).
+// RunTestWithBp(t, bp)
+//
+// foo := result.ModuleForTests("foo", "android_common")
+// sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
+// if !strings.Contains(*sboxProto.Commands[0].Command,
+// "--baseline lint-baseline.xml --disallowed_issues NewApi") {
+// t.Error("did not restrict baselining NewApi")
+// }
+//
+// bar := result.ModuleForTests("bar", "android_common")
+// sboxProto = android.RuleBuilderSboxProtoForTests(t, bar.Output("lint.sbox.textproto"))
+// if !strings.Contains(*sboxProto.Commands[0].Command,
+// "--baseline lint-baseline.xml --disallowed_issues NewApi") {
+// t.Error("did not restrict baselining NewApi")
+// }
+//}
func TestJavaLintDatabaseSelectionFull(t *testing.T) {
- testCases := []string{
- "current", "core_platform", "system_current", "S", "30", "10000",
+ testCases := []struct {
+ sdk_version string
+ expected_file string
+ }{
+ {
+ "current",
+ "api_versions_public.xml",
+ }, {
+ "core_platform",
+ "api_versions_public.xml",
+ }, {
+ "system_current",
+ "api_versions_system.xml",
+ }, {
+ "module_current",
+ "api_versions_module_lib.xml",
+ }, {
+ "system_server_current",
+ "api_versions_system_server.xml",
+ }, {
+ "S",
+ "api_versions_public.xml",
+ }, {
+ "30",
+ "api_versions_public.xml",
+ }, {
+ "10000",
+ "api_versions_public.xml",
+ },
}
bp := `
java_library {
@@ -238,7 +267,7 @@ func TestJavaLintDatabaseSelectionFull(t *testing.T) {
}
`
for _, testCase := range testCases {
- thisBp := strings.Replace(bp, "XXX", testCase, 1)
+ thisBp := strings.Replace(bp, "XXX", testCase.sdk_version, 1)
result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules, FixtureWithPrebuiltApis(map[string][]string{
"30": {"foo"},
@@ -248,49 +277,8 @@ func TestJavaLintDatabaseSelectionFull(t *testing.T) {
foo := result.ModuleForTests("foo", "android_common")
sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
- if strings.Contains(*sboxProto.Commands[0].Command,
- "/api_versions_public_filtered.xml") {
- t.Error("used public-filtered lint api database for case", testCase)
- }
- if !strings.Contains(*sboxProto.Commands[0].Command,
- "/api_versions.xml") {
+ if !strings.Contains(*sboxProto.Commands[0].Command, "/"+testCase.expected_file) {
t.Error("did not use full api database for case", testCase)
}
}
-
-}
-
-func TestJavaLintDatabaseSelectionPublicFiltered(t *testing.T) {
- testCases := []string{
- "module_current", "system_server_current",
- }
- bp := `
- java_library {
- name: "foo",
- srcs: [
- "a.java",
- ],
- min_sdk_version: "29",
- sdk_version: "XXX",
- lint: {
- strict_updatability_linting: true,
- },
- }
-`
- for _, testCase := range testCases {
- thisBp := strings.Replace(bp, "XXX", testCase, 1)
- result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules).
- RunTestWithBp(t, thisBp)
-
- foo := result.ModuleForTests("foo", "android_common")
- sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
- if !strings.Contains(*sboxProto.Commands[0].Command,
- "/api_versions_public_filtered.xml") {
- t.Error("did not use public-filtered lint api database for case", testCase)
- }
- if strings.Contains(*sboxProto.Commands[0].Command,
- "/api_versions.xml") {
- t.Error("used full api database for case", testCase)
- }
- }
}
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index f0de7a4d8..0ea360979 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -129,7 +129,7 @@ func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.Botto
// Add dependencies on all the non-updatable module configured in the "boot" boot image. That does
// not include modules configured in the "art" boot image.
- bootImageConfig := b.getImageConfig(ctx)
+ bootImageConfig := defaultBootImageConfig(ctx)
addDependenciesOntoBootImageModules(ctx, bootImageConfig.modules, platformBootclasspathBootJarDepTag)
// Add dependencies on all the apex jars.
@@ -205,7 +205,7 @@ func (b *platformBootclasspathModule) generateClasspathProtoBuildActions(ctx and
func (b *platformBootclasspathModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList {
// Include all non APEX jars
- jars := b.getImageConfig(ctx).modules
+ jars := defaultBootImageConfig(ctx).modules
// Include jars from APEXes that don't populate their classpath proto config.
remainingJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
@@ -266,10 +266,6 @@ func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext
}
}
-func (b *platformBootclasspathModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
- return defaultBootImageConfig(ctx)
-}
-
// generateHiddenAPIBuildActions generates all the hidden API related build rules.
func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module, fragments []android.Module) bootDexJarByModule {
@@ -410,27 +406,25 @@ func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.
// GenerateSingletonBuildActions method as it cannot create it for itself.
dexpreopt.GetGlobalSoongConfig(ctx)
- imageConfig := b.getImageConfig(ctx)
- if imageConfig == nil {
- return
- }
-
global := dexpreopt.GetGlobalConfig(ctx)
if !shouldBuildBootImages(ctx.Config(), global) {
return
}
- // Generate the framework profile rule
- bootFrameworkProfileRule(ctx, imageConfig)
+ frameworkBootImageConfig := defaultBootImageConfig(ctx)
+ bootFrameworkProfileRule(ctx, frameworkBootImageConfig)
+ b.generateBootImage(ctx, frameworkBootImageName, platformModules)
+ b.generateBootImage(ctx, mainlineBootImageName, apexModules)
+ b.copyApexBootJarsForAppsDexpreopt(ctx, apexModules)
+ dumpOatRules(ctx, frameworkBootImageConfig)
+}
- // Copy platform module dex jars to their predefined locations.
- platformBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, platformModules)
- copyBootJarsToPredefinedLocations(ctx, platformBootDexJarsByModule, imageConfig.dexPathsByModule)
+func (b *platformBootclasspathModule) generateBootImage(ctx android.ModuleContext, imageName string, modules []android.Module) {
+ imageConfig := genBootImageConfigs(ctx)[imageName]
- // Copy apex module dex jars to their predefined locations.
- config := GetApexBootConfig(ctx)
- apexBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, apexModules)
- copyBootJarsToPredefinedLocations(ctx, apexBootDexJarsByModule, config.dexPathsByModule)
+ // Copy module dex jars to their predefined locations.
+ bootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, modules)
+ copyBootJarsToPredefinedLocations(ctx, bootDexJarsByModule, imageConfig.dexPathsByModule)
// Build a profile for the image config and then use that to build the boot image.
profile := bootImageProfileRule(ctx, imageConfig)
@@ -443,6 +437,11 @@ func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.
// Build boot image files for the host variants. There are use directly by ART host side tests.
buildBootImageVariantsForBuildOs(ctx, imageConfig, profile)
+}
- dumpOatRules(ctx, imageConfig)
+// Copy apex module dex jars to their predefined locations. They will be used for dexpreopt for apps.
+func (b *platformBootclasspathModule) copyApexBootJarsForAppsDexpreopt(ctx android.ModuleContext, apexModules []android.Module) {
+ config := GetApexBootConfig(ctx)
+ apexBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, apexModules)
+ copyBootJarsToPredefinedLocations(ctx, apexBootDexJarsByModule, config.dexPathsByModule)
}
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index c6acd55e5..206d99527 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -264,7 +264,7 @@ func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) {
}
// Sort the keys in order to make build.ninja stable
- for _, k := range android.SortedStringKeys(latest) {
+ for _, k := range android.SortedKeys(latest) {
info := latest[k]
name := PrebuiltApiModuleName(info.module, info.scope, "latest")
createApiModule(mctx, name, info.path)
@@ -284,7 +284,7 @@ func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) {
}
}
// Create empty incompatibilities files for remaining modules
- for _, k := range android.SortedStringKeys(latest) {
+ for _, k := range android.SortedKeys(latest) {
if _, ok := incompatibilities[k]; !ok {
createEmptyFile(mctx, PrebuiltApiModuleName(latest[k].module+"-incompatibilities", latest[k].scope, "latest"))
}
diff --git a/java/robolectric.go b/java/robolectric.go
index 68f27b859..008b8b1c9 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -302,6 +302,9 @@ func (r *robolectricTest) AndroidMkEntries() []android.AndroidMkEntries {
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", "robolectric-tests")
+ if r.testConfig != nil {
+ entries.SetPath("LOCAL_FULL_TEST_CONFIG", r.testConfig)
+ }
})
entries.ExtraFooters = []android.AndroidMkExtraFootersFunc{
diff --git a/java/sdk.go b/java/sdk.go
index b0da5afba..10ae3f6e8 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -57,14 +57,10 @@ func defaultJavaLanguageVersion(ctx android.EarlyModuleContext, s android.SdkSpe
return JAVA_VERSION_8
} else if sdk.FinalOrFutureInt() <= 31 {
return JAVA_VERSION_9
- } else if ctx.Config().TargetsJava17() {
- // Temporary experimental flag to be able to try and build with
- // java version 17 options. The flag, if used, just sets Java
- // 17 as the default version, leaving any components that
- // target an older version intact.
- return JAVA_VERSION_17
- } else {
+ } else if sdk.FinalOrFutureInt() <= 32 {
return JAVA_VERSION_11
+ } else {
+ return JAVA_VERSION_17
}
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index b87236596..d2fbfd953 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -28,6 +28,7 @@ import (
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/bazel"
"android/soong/dexpreopt"
)
@@ -546,14 +547,14 @@ type sdkLibraryProperties struct {
// The properties specific to the module-lib api scope
//
- // Unless explicitly specified by using test.enabled the module-lib api scope is
- // disabled by default.
+ // Unless explicitly specified by using module_lib.enabled the module_lib api
+ // scope is disabled by default.
Module_lib ApiScopeProperties
// The properties specific to the system-server api scope
//
- // Unless explicitly specified by using test.enabled the module-lib api scope is
- // disabled by default.
+ // Unless explicitly specified by using system_server.enabled the
+ // system_server api scope is disabled by default.
System_server ApiScopeProperties
// Determines if the stubs are preferred over the implementation library
@@ -1163,6 +1164,8 @@ type SdkLibraryDependency interface {
type SdkLibrary struct {
Library
+ android.BazelModuleBase
+
sdkLibraryProperties sdkLibraryProperties
// Map from api scope to the scope specific property structure.
@@ -1376,7 +1379,7 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext)
})
// Make the set of components exported by this module available for use elsewhere.
- exportedComponentInfo := android.ExportedComponentsInfo{Components: android.SortedStringKeys(exportedComponents)}
+ exportedComponentInfo := android.ExportedComponentsInfo{Components: android.SortedKeys(exportedComponents)}
ctx.SetProvider(android.ExportedComponentsInfoProvider, exportedComponentInfo)
// Provide additional information for inclusion in an sdk's generated .info file.
@@ -1749,7 +1752,7 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC
}
}
- mctx.CreateModule(DroidstubsFactory, &props)
+ mctx.CreateModule(DroidstubsFactory, &props).(*Droidstubs).CallHookIfAvailable(mctx)
}
func (module *SdkLibrary) compareAgainstLatestApi(apiScope *apiScope) bool {
@@ -2081,9 +2084,48 @@ func SdkLibraryFactory() android.Module {
module.CreateInternalModules(ctx)
}
})
+ android.InitBazelModule(module)
return module
}
+type bazelSdkLibraryAttributes struct {
+ Public bazel.StringAttribute
+ System bazel.StringAttribute
+ Test bazel.StringAttribute
+ Module_lib bazel.StringAttribute
+ System_server bazel.StringAttribute
+}
+
+// java_sdk_library bp2build converter
+func (module *SdkLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ if ctx.ModuleType() != "java_sdk_library" {
+ return
+ }
+
+ nameToAttr := make(map[string]bazel.StringAttribute)
+
+ for _, scope := range module.getGeneratedApiScopes(ctx) {
+ apiSurfaceFile := path.Join(module.getApiDir(), scope.apiFilePrefix+"current.txt")
+ var scopeStringAttribute bazel.StringAttribute
+ scopeStringAttribute.SetValue(apiSurfaceFile)
+ nameToAttr[scope.name] = scopeStringAttribute
+ }
+
+ attrs := bazelSdkLibraryAttributes{
+ Public: nameToAttr["public"],
+ System: nameToAttr["system"],
+ Test: nameToAttr["test"],
+ Module_lib: nameToAttr["module-lib"],
+ System_server: nameToAttr["system-server"],
+ }
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "java_sdk_library",
+ Bzl_load_location: "//build/bazel/rules/java:sdk_library.bzl",
+ }
+
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, &attrs)
+}
+
//
// SDK library prebuilts
//
@@ -2201,7 +2243,7 @@ func sdkLibraryImportFactory() android.Module {
allScopeProperties, scopeToProperties := createPropertiesInstance()
module.scopeProperties = scopeToProperties
- module.AddProperties(&module.properties, allScopeProperties)
+ module.AddProperties(&module.properties, allScopeProperties, &module.importDexpreoptProperties)
// Initialize information common between source and prebuilt.
module.initCommon(module)
@@ -2445,18 +2487,24 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo
if di == nil {
return // An error has been reported by FindDeapexerProviderForModule.
}
- if dexOutputPath := di.PrebuiltExportPath(apexRootRelativePathToJavaLib(module.BaseModuleName())); dexOutputPath != nil {
+ dexJarFileApexRootRelative := apexRootRelativePathToJavaLib(module.BaseModuleName())
+ if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil {
dexJarFile := makeDexJarPathFromPath(dexOutputPath)
module.dexJarFile = dexJarFile
installPath := android.PathForModuleInPartitionInstall(
- ctx, "apex", ai.ApexVariationName, apexRootRelativePathToJavaLib(module.BaseModuleName()))
+ ctx, "apex", ai.ApexVariationName, dexJarFileApexRootRelative)
module.installFile = installPath
module.initHiddenAPI(ctx, dexJarFile, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil)
- // Dexpreopting.
module.dexpreopter.installPath = module.dexpreopter.getInstallPath(ctx, installPath)
module.dexpreopter.isSDKLibrary = true
module.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &module.dexpreopter)
+
+ if profilePath := di.PrebuiltExportPath(dexJarFileApexRootRelative + ".prof"); profilePath != nil {
+ module.dexpreopter.inputProfilePathOnHost = profilePath
+ }
+
+ // Dexpreopting.
module.dexpreopt(ctx, dexOutputPath)
} else {
// This should never happen as a variant for a prebuilt_apex is only created if the
@@ -2585,7 +2633,7 @@ var _ android.RequiredFilesFromPrebuiltApex = (*SdkLibraryImport)(nil)
func (module *SdkLibraryImport) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) []string {
name := module.BaseModuleName()
- return requiredFilesFromPrebuiltApexForImport(name)
+ return requiredFilesFromPrebuiltApexForImport(name, &module.dexpreopter)
}
// java_sdk_library_xml
@@ -2994,6 +3042,8 @@ type sdkLibrarySdkMemberProperties struct {
//
// This means that the device won't recognise this library as installed.
Max_device_sdk *string
+
+ DexPreoptProfileGuided *bool `supported_build_releases:"UpsideDownCake+"`
}
type scopeProperties struct {
@@ -3047,6 +3097,10 @@ func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMembe
s.On_bootclasspath_before = sdk.commonSdkLibraryProperties.On_bootclasspath_before
s.Min_device_sdk = sdk.commonSdkLibraryProperties.Min_device_sdk
s.Max_device_sdk = sdk.commonSdkLibraryProperties.Max_device_sdk
+
+ if sdk.dexpreopter.dexpreoptProperties.Dex_preopt_result.Profile_guided {
+ s.DexPreoptProfileGuided = proptools.BoolPtr(true)
+ }
}
func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
@@ -3062,6 +3116,10 @@ func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberCo
if len(s.Permitted_packages) > 0 {
propertySet.AddProperty("permitted_packages", s.Permitted_packages)
}
+ dexPreoptSet := propertySet.AddPropertySet("dex_preopt")
+ if s.DexPreoptProfileGuided != nil {
+ dexPreoptSet.AddProperty("profile_guided", proptools.Bool(s.DexPreoptProfileGuided))
+ }
stem := s.Stem
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 210bfc3a3..1d0c13d4b 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -120,6 +120,7 @@ func TestJavaSdkLibrary(t *testing.T) {
result.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo"), "android_common")
result.ModuleForTests(apiScopeSystem.stubsSourceModuleName("foo"), "android_common")
result.ModuleForTests(apiScopeTest.stubsSourceModuleName("foo"), "android_common")
+ result.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo")+".api.contribution", "")
result.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
result.ModuleForTests("foo.api.public.28", "")
result.ModuleForTests("foo.api.system.28", "")
diff --git a/java/testing.go b/java/testing.go
index e6f76e10d..63d7dba69 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -198,7 +198,7 @@ func FixtureWithPrebuiltApisAndExtensions(apiLevel2Modules map[string][]string,
imports_sdk_version: "none",
imports_compile_dex: true,
}
- `, strings.Join(android.SortedStringKeys(apiLevel2Modules), `", "`))
+ `, strings.Join(android.SortedKeys(apiLevel2Modules), `", "`))
for release, modules := range apiLevel2Modules {
mockFS.Merge(prebuiltApisFilesForModules([]string{release}, modules))
diff --git a/licenses/OWNERS b/licenses/OWNERS
deleted file mode 100644
index fddfc4889..000000000
--- a/licenses/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file * = bbadour@google.com
-
diff --git a/linkerconfig/proto/OWNERS b/linkerconfig/proto/OWNERS
deleted file mode 100644
index 31f0460a1..000000000
--- a/linkerconfig/proto/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-kiyoungkim@google.com
-jiyong@google.com
-jooyung@google.com
diff --git a/python/python.go b/python/python.go
index 18e5b68dd..0ae7b3691 100644
--- a/python/python.go
+++ b/python/python.go
@@ -532,7 +532,7 @@ func (p *PythonLibraryModule) createSrcsZip(ctx android.ModuleContext, pkgPath s
if len(relativeRootMap) > 0 {
// in order to keep stable order of soong_zip params, we sort the keys here.
- roots := android.SortedStringKeys(relativeRootMap)
+ roots := android.SortedKeys(relativeRootMap)
// Use -symlinks=false so that the symlinks in the bazel output directory are followed
parArgs := []string{"-symlinks=false"}
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 32c746ed4..20e991967 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -205,8 +205,8 @@ func (compiler *baseCompiler) AndroidMk(ctx AndroidMkContext, ret *android.Andro
})
}
-func (fuzz *fuzzDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
- ctx.SubAndroidMk(entries, fuzz.binaryDecorator)
+func (fuzz *fuzzDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
+ ctx.SubAndroidMk(ret, fuzz.binaryDecorator)
var fuzzFiles []string
for _, d := range fuzz.fuzzPackagedModule.Corpus {
@@ -229,11 +229,14 @@ func (fuzz *fuzzDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *andro
filepath.Dir(fuzz.fuzzPackagedModule.Config.String())+":config.json")
}
- entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext,
+ ret.ExtraEntries = append(ret.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext,
entries *android.AndroidMkEntries) {
entries.SetBool("LOCAL_IS_FUZZ_TARGET", true)
if len(fuzzFiles) > 0 {
entries.AddStrings("LOCAL_TEST_DATA", fuzzFiles...)
}
+ if fuzz.installedSharedDeps != nil {
+ entries.AddStrings("LOCAL_FUZZ_INSTALLED_SHARED_DEPS", fuzz.installedSharedDeps...)
+ }
})
}
diff --git a/rust/bindgen.go b/rust/bindgen.go
index e81ec6bf6..8cec918d3 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -52,7 +52,7 @@ var (
if ctx.Config().UseHostMusl() {
return "musl/lib/"
} else {
- return "lib64/"
+ return "lib/"
}
})
_ = pctx.SourcePathVariable("bindgenClang",
@@ -313,7 +313,7 @@ func NewRustBindgen(hod android.HostOrDeviceSupported) (*Module, *bindgenDecorat
func (b *bindgenDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps {
deps = b.BaseSourceProvider.SourceProviderDeps(ctx, deps)
- if ctx.toolchain().Bionic() {
+ if ctx.toolchain().Bionic() && !ctx.RustModule().compiler.noStdlibs() {
deps = bionicDeps(ctx, deps, false)
} else if ctx.Os() == android.LinuxMusl {
deps = muslDeps(ctx, deps, false)
diff --git a/rust/builder.go b/rust/builder.go
index 7dd9dd276..a2f1238c2 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -247,7 +247,13 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl
if ctx.Config().IsEnvTrue("SOONG_RUSTC_INCREMENTAL") {
incrementalPath := android.PathForOutput(ctx, "rustc").String()
- rustcFlags = append(rustcFlags, "-C incremental="+incrementalPath)
+ rustcFlags = append(rustcFlags, "-Cincremental="+incrementalPath)
+ }
+
+ // Disallow experimental features
+ modulePath := android.PathForModuleSrc(ctx).String()
+ if !(android.IsThirdPartyPath(modulePath) || strings.HasPrefix(modulePath, "prebuilts")) {
+ rustcFlags = append(rustcFlags, "-Zallow-features=\"default_alloc_error_handler,custom_inner_attributes,mixed_integer_ops,slice_internals\"")
}
// Collect linker flags
@@ -399,7 +405,7 @@ func Rustdoc(ctx ModuleContext, main android.Path, deps PathDeps,
// Silence warnings about renamed lints for third-party crates
modulePath := android.PathForModuleSrc(ctx).String()
if android.IsThirdPartyPath(modulePath) {
- rustdocFlags = append(rustdocFlags, " -A renamed_and_removed_lints")
+ rustdocFlags = append(rustdocFlags, " -A warnings")
}
// Yes, the same out directory is used simultaneously by all rustdoc builds.
diff --git a/rust/compiler.go b/rust/compiler.go
index 8ec42f079..06ae12f79 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -208,6 +208,10 @@ func (compiler *baseCompiler) SetDisabled() {
panic("baseCompiler does not implement SetDisabled()")
}
+func (compiler *baseCompiler) noStdlibs() bool {
+ return Bool(compiler.Properties.No_stdlibs)
+}
+
func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath {
panic("baseCompiler does not implement coverageOutputZipPath()")
}
@@ -265,6 +269,11 @@ func (compiler *baseCompiler) featureFlags(ctx ModuleContext, flags Flags) Flags
func (compiler *baseCompiler) cfgFlags(ctx ModuleContext, flags Flags) Flags {
if ctx.RustModule().UseVndk() {
compiler.Properties.Cfgs = append(compiler.Properties.Cfgs, "android_vndk")
+ if ctx.RustModule().InVendor() {
+ compiler.Properties.Cfgs = append(compiler.Properties.Cfgs, "android_vendor")
+ } else if ctx.RustModule().InProduct() {
+ compiler.Properties.Cfgs = append(compiler.Properties.Cfgs, "android_product")
+ }
}
flags.RustFlags = append(flags.RustFlags, compiler.cfgsToFlags()...)
diff --git a/rust/config/global.go b/rust/config/global.go
index 50ac1f72a..0dface47b 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@ import (
var pctx = android.NewPackageContext("android/soong/rust/config")
var (
- RustDefaultVersion = "1.65.0.p1"
+ RustDefaultVersion = "1.67.1"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2021"
Stdlibs = []string{
diff --git a/rust/config/x86_linux_bionic_host.go b/rust/config/x86_linux_bionic_host.go
index b1a2c178e..79c40ce41 100644
--- a/rust/config/x86_linux_bionic_host.go
+++ b/rust/config/x86_linux_bionic_host.go
@@ -21,7 +21,9 @@ import (
)
var (
- LinuxBionicRustFlags = []string{}
+ LinuxBionicRustFlags = []string{
+ "-C panic=abort",
+ }
LinuxBionicRustLinkFlags = []string{
"-B${cc_config.ClangBin}",
"-fuse-ld=lld",
diff --git a/rust/coverage.go b/rust/coverage.go
index 5ea481fcf..bc6504ddc 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -21,6 +21,7 @@ import (
)
var CovLibraryName = "libprofile-clang-extras"
+var ProfilerBuiltins = "libprofiler_builtins.rust_sysroot"
// Add '%c' to default specifier after we resolve http://b/210012154
const profileInstrFlag = "-fprofile-instr-generate=/data/misc/trace/clang-%p-%m.profraw"
@@ -41,6 +42,11 @@ func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps {
ctx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
}, cc.CoverageDepTag, CovLibraryName)
+
+ // no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency.
+ if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() {
+ ctx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}, rlibDepTag, ProfilerBuiltins)
+ }
}
return deps
@@ -60,6 +66,13 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags
flags.LinkFlags = append(flags.LinkFlags,
profileInstrFlag, "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,open")
deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path())
+
+ // no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency.
+ if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() {
+ profiler_builtins := ctx.GetDirectDepWithTag(ProfilerBuiltins, rlibDepTag).(*Module)
+ deps.RLibs = append(deps.RLibs, RustLibrary{Path: profiler_builtins.OutputFile().Path(), CrateName: profiler_builtins.CrateName()})
+ }
+
if cc.EnableContinuousCoverage(ctx) {
flags.RustFlags = append(flags.RustFlags, "-C llvm-args=--runtime-counter-relocation")
flags.LinkFlags = append(flags.LinkFlags, "-Wl,-mllvm,-runtime-counter-relocation")
diff --git a/rust/fuzz.go b/rust/fuzz.go
index 6faf55cf6..d7e7ddfff 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -16,8 +16,6 @@ package rust
import (
"path/filepath"
- "sort"
- "strings"
"android/soong/android"
"android/soong/cc"
@@ -27,14 +25,14 @@ import (
func init() {
android.RegisterModuleType("rust_fuzz", RustFuzzFactory)
- android.RegisterSingletonType("rust_fuzz_packaging", rustFuzzPackagingFactory)
}
type fuzzDecorator struct {
*binaryDecorator
- fuzzPackagedModule fuzz.FuzzPackagedModule
- sharedLibraries android.Paths
+ fuzzPackagedModule fuzz.FuzzPackagedModule
+ sharedLibraries android.Paths
+ installedSharedDeps []string
}
var _ compiler = (*fuzzDecorator)(nil)
@@ -64,9 +62,14 @@ func (fuzzer *fuzzDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags
flags = fuzzer.binaryDecorator.compilerFlags(ctx, flags)
// `../lib` for installed fuzz targets (both host and device), and `./lib` for fuzz target packages.
- flags.LinkFlags = append(flags.LinkFlags, `-Wl,-rpath,\$$ORIGIN/../lib`)
flags.LinkFlags = append(flags.LinkFlags, `-Wl,-rpath,\$$ORIGIN/lib`)
+ if ctx.InstallInVendor() {
+ flags.LinkFlags = append(flags.LinkFlags, `-Wl,-rpath,\$$ORIGIN/../../lib`)
+ } else {
+ flags.LinkFlags = append(flags.LinkFlags, `-Wl,-rpath,\$$ORIGIN/../lib`)
+
+ }
return flags
}
@@ -88,10 +91,8 @@ func (fuzzer *fuzzDecorator) compilerProps() []interface{} {
}
func (fuzzer *fuzzDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
- out := fuzzer.binaryDecorator.compile(ctx, flags, deps)
- // Grab the list of required shared libraries.
- fuzzer.sharedLibraries, _ = cc.CollectAllSharedDependencies(ctx)
+ out := fuzzer.binaryDecorator.compile(ctx, flags, deps)
return out
}
@@ -104,83 +105,6 @@ func (fuzzer *fuzzDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep
return rlibAutoDep
}
-// Responsible for generating GNU Make rules that package fuzz targets into
-// their architecture & target/host specific zip file.
-type rustFuzzPackager struct {
- fuzz.FuzzPackager
-}
-
-func rustFuzzPackagingFactory() android.Singleton {
- return &rustFuzzPackager{}
-}
-
-func (s *rustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
- // Map between each architecture + host/device combination.
- archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip)
-
- // List of individual fuzz targets.
- s.FuzzTargets = make(map[string]bool)
-
- // Map tracking whether each shared library has an install rule to avoid duplicate install rules from
- // multiple fuzzers that depend on the same shared library.
- sharedLibraryInstalled := make(map[string]bool)
-
- ctx.VisitAllModules(func(module android.Module) {
- // Discard non-fuzz targets.
- rustModule, ok := module.(*Module)
- if !ok {
- return
- }
-
- if ok := fuzz.IsValid(rustModule.FuzzModule); !ok || rustModule.Properties.PreventInstall {
- return
- }
-
- fuzzModule, ok := rustModule.compiler.(*fuzzDecorator)
- if !ok {
- return
- }
-
- hostOrTargetString := "target"
- if rustModule.Host() {
- hostOrTargetString = "host"
- }
-
- archString := rustModule.Arch().ArchType.String()
- archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
- archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
-
- var files []fuzz.FileToZip
- builder := android.NewRuleBuilder(pctx, ctx)
-
- // Package the artifacts (data, corpus, config and dictionary into a zipfile.
- files = s.PackageArtifacts(ctx, module, fuzzModule.fuzzPackagedModule, archDir, builder)
-
- // The executable.
- files = append(files, fuzz.FileToZip{rustModule.UnstrippedOutputFile(), ""})
-
- // Package shared libraries
- files = append(files, cc.GetSharedLibsToZip(fuzzModule.sharedLibraries, rustModule, &s.FuzzPackager, archString, "lib", &sharedLibraryInstalled)...)
-
- archDirs[archOs], ok = s.BuildZipFile(ctx, module, fuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
- if !ok {
- return
- }
-
- })
- s.CreateFuzzPackage(ctx, archDirs, fuzz.Rust, pctx)
-}
-
-func (s *rustFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
- packages := s.Packages.Strings()
- sort.Strings(packages)
-
- ctx.Strict("SOONG_RUST_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(packages, " "))
-
- // Preallocate the slice of fuzz targets to minimize memory allocations.
- s.PreallocateSlice(ctx, "ALL_RUST_FUZZ_TARGETS")
-}
-
func (fuzz *fuzzDecorator) install(ctx ModuleContext) {
fuzz.binaryDecorator.baseCompiler.dir = filepath.Join(
"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
@@ -188,13 +112,22 @@ func (fuzz *fuzzDecorator) install(ctx ModuleContext) {
"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
fuzz.binaryDecorator.baseCompiler.install(ctx)
- if fuzz.fuzzPackagedModule.FuzzProperties.Corpus != nil {
- fuzz.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzz.fuzzPackagedModule.FuzzProperties.Corpus)
- }
- if fuzz.fuzzPackagedModule.FuzzProperties.Data != nil {
- fuzz.fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzz.fuzzPackagedModule.FuzzProperties.Data)
- }
- if fuzz.fuzzPackagedModule.FuzzProperties.Dictionary != nil {
- fuzz.fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzz.fuzzPackagedModule.FuzzProperties.Dictionary)
+ fuzz.fuzzPackagedModule = cc.PackageFuzzModule(ctx, fuzz.fuzzPackagedModule, pctx)
+
+ installBase := "fuzz"
+
+ // Grab the list of required shared libraries.
+ fuzz.sharedLibraries, _ = cc.CollectAllSharedDependencies(ctx)
+
+ for _, lib := range fuzz.sharedLibraries {
+ fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
+ cc.SharedLibraryInstallLocation(
+ lib, ctx.Host(), installBase, ctx.Arch().ArchType.String()))
+
+ // Also add the dependency on the shared library symbols dir.
+ if !ctx.Host() {
+ fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
+ cc.SharedLibrarySymbolsInstallLocation(lib, installBase, ctx.Arch().ArchType.String()))
+ }
}
}
diff --git a/rust/image_test.go b/rust/image_test.go
index 818587218..fb4d9c170 100644
--- a/rust/image_test.go
+++ b/rust/image_test.go
@@ -53,6 +53,7 @@ func TestImageVndkCfgFlag(t *testing.T) {
crate_name: "foo",
srcs: ["foo.rs"],
vendor_available: true,
+ product_available: true,
}
`)
@@ -61,6 +62,35 @@ func TestImageVndkCfgFlag(t *testing.T) {
if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vndk'") {
t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
}
+ if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vendor'") {
+ t.Errorf("missing \"--cfg 'android_vendor'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
+ }
+ if strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_product'") {
+ t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
+ }
+
+ product := ctx.ModuleForTests("libfoo", "android_product.29_arm64_armv8-a_static").Rule("rustc")
+ if !strings.Contains(product.Args["rustcFlags"], "--cfg 'android_vndk'") {
+ t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
+ }
+ if strings.Contains(product.Args["rustcFlags"], "--cfg 'android_vendor'") {
+ t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
+ }
+ if !strings.Contains(product.Args["rustcFlags"], "--cfg 'android_product'") {
+ t.Errorf("missing \"--cfg 'android_product'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
+ }
+
+ system := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Rule("rustc")
+ if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_vndk'") {
+ t.Errorf("unexpected \"--cfg 'android_vndk'\" for libfoo system variant, rustcFlags: %#v", system.Args["rustcFlags"])
+ }
+ if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_vendor'") {
+ t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo system variant, rustcFlags: %#v", system.Args["rustcFlags"])
+ }
+ if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_product'") {
+ t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo system variant, rustcFlags: %#v", product.Args["rustcFlags"])
+ }
+
}
// Test that cc modules can link against vendor_ramdisk_available rust_ffi_static libraries.
diff --git a/rust/rust.go b/rust/rust.go
index 28a300bc6..8a13ba364 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -62,11 +62,11 @@ type Flags struct {
}
type BaseProperties struct {
- AndroidMkRlibs []string
- AndroidMkDylibs []string
- AndroidMkProcMacroLibs []string
- AndroidMkSharedLibs []string
- AndroidMkStaticLibs []string
+ AndroidMkRlibs []string `blueprint:"mutated"`
+ AndroidMkDylibs []string `blueprint:"mutated"`
+ AndroidMkProcMacroLibs []string `blueprint:"mutated"`
+ AndroidMkSharedLibs []string `blueprint:"mutated"`
+ AndroidMkStaticLibs []string `blueprint:"mutated"`
ImageVariationPrefix string `blueprint:"mutated"`
VndkVersion string `blueprint:"mutated"`
@@ -208,6 +208,11 @@ func (mod *Module) OutputFiles(tag string) (android.Paths, error) {
}
return android.Paths{}, nil
}
+ case "unstripped":
+ if mod.compiler != nil {
+ return android.PathsIfNonNil(mod.compiler.unstrippedOutputFilePath()), nil
+ }
+ return nil, nil
default:
return nil, fmt.Errorf("unsupported module reference tag %q", tag)
}
@@ -485,6 +490,7 @@ type compiler interface {
SetDisabled()
stdLinkage(ctx *depsContext) RustLinkage
+ noStdlibs() bool
unstrippedOutputFilePath() android.Path
strippedOutputFilePath() android.OptionalPath
@@ -619,6 +625,31 @@ func (mod *Module) CcLibraryInterface() bool {
return false
}
+func (mod *Module) IsFuzzModule() bool {
+ if _, ok := mod.compiler.(*fuzzDecorator); ok {
+ return true
+ }
+ return false
+}
+
+func (mod *Module) FuzzModuleStruct() fuzz.FuzzModule {
+ return mod.FuzzModule
+}
+
+func (mod *Module) FuzzPackagedModule() fuzz.FuzzPackagedModule {
+ if fuzzer, ok := mod.compiler.(*fuzzDecorator); ok {
+ return fuzzer.fuzzPackagedModule
+ }
+ panic(fmt.Errorf("FuzzPackagedModule called on non-fuzz module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) FuzzSharedLibraries() android.Paths {
+ if fuzzer, ok := mod.compiler.(*fuzzDecorator); ok {
+ return fuzzer.sharedLibraries
+ }
+ panic(fmt.Errorf("FuzzSharedLibraries called on non-fuzz module: %q", mod.BaseModuleName()))
+}
+
func (mod *Module) UnstrippedOutputFile() android.Path {
if mod.compiler != nil {
return mod.compiler.unstrippedOutputFilePath()
diff --git a/scripts/OWNERS b/scripts/OWNERS
deleted file mode 100644
index 7b003fd6a..000000000
--- a/scripts/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-per-file system-clang-format,system-clang-format-2 = enh@google.com,smoreland@google.com
-per-file construct_context.py = ngeoffray@google.com,calin@google.com,skvadrik@google.com
-per-file conv_linker_config.py = kiyoungkim@google.com, jiyong@google.com, jooyung@google.com
-per-file gen_ndk*.sh,gen_java*.sh = sophiez@google.com, allenhair@google.com
diff --git a/scripts/check_boot_jars/package_allowed_list.txt b/scripts/check_boot_jars/package_allowed_list.txt
index 08bd80cab..ce461b13c 100644
--- a/scripts/check_boot_jars/package_allowed_list.txt
+++ b/scripts/check_boot_jars/package_allowed_list.txt
@@ -8,6 +8,7 @@ java\.beans
java\.io
java\.lang
java\.lang\.annotation
+java\.lang\.constant
java\.lang\.invoke
java\.lang\.ref
java\.lang\.reflect
diff --git a/scripts/test_config_fixer.py b/scripts/test_config_fixer.py
index 3dbc22ec2..07e01a14a 100644
--- a/scripts/test_config_fixer.py
+++ b/scripts/test_config_fixer.py
@@ -31,6 +31,8 @@ from manifest import write_xml
KNOWN_PREPARERS = ['com.android.tradefed.targetprep.TestAppInstallSetup',
'com.android.tradefed.targetprep.suite.SuiteApkInstaller']
+MAINLINE_CONTROLLER = 'com.android.tradefed.testtype.suite.module.MainlineTestModuleController'
+
def parse_args():
"""Parse commandline arguments."""
@@ -41,6 +43,8 @@ def parse_args():
help=('overwrite package fields in the test config'))
parser.add_argument('--test-file-name', default='', dest='test_file_name',
help=('overwrite test file name in the test config'))
+ parser.add_argument('--mainline-package-name', default='', dest='mainline_package_name',
+ help=('overwrite mainline module package name in the test config'))
parser.add_argument('input', help='input test config file')
parser.add_argument('output', help='output test config file')
return parser.parse_args()
@@ -72,6 +76,16 @@ def overwrite_test_file_name(test_config_doc, test_file_name):
if option.getAttribute('name') == "test-file-name":
option.setAttribute('value', test_file_name)
+def overwrite_mainline_module_package_name(test_config_doc, mainline_package_name):
+
+ test_config = parse_test_config(test_config_doc)
+
+ for obj in get_children_with_tag(test_config, 'object'):
+ if obj.getAttribute('class') == MAINLINE_CONTROLLER:
+ for option in get_children_with_tag(obj, 'option'):
+ if option.getAttribute('name') == "mainline-module-package-name":
+ option.setAttribute('value', mainline_package_name)
+
def main():
"""Program entry point."""
try:
@@ -88,6 +102,9 @@ def main():
if args.test_file_name:
overwrite_test_file_name(doc, args.test_file_name)
+ if args.mainline_package_name:
+ overwrite_mainline_module_package_name(doc, args.mainline_package_name)
+
with open(args.output, 'w') as f:
write_xml(f, doc)
diff --git a/scripts/test_config_fixer_test.py b/scripts/test_config_fixer_test.py
index 39ce5b3c3..699f91eeb 100644
--- a/scripts/test_config_fixer_test.py
+++ b/scripts/test_config_fixer_test.py
@@ -23,6 +23,8 @@ from xml.dom import minidom
import test_config_fixer
+from manifest import write_xml
+
sys.dont_write_bytecode = True
@@ -117,5 +119,39 @@ class OverwriteTestFileNameTest(unittest.TestCase):
self.assertEqual(expected, output.getvalue())
+class OverwriteMainlineModulePackageNameTest(unittest.TestCase):
+ """ Unit tests for overwrite_mainline_module_package_name function """
+
+ test_config = (
+ '<?xml version="1.0" encoding="utf-8"?>\n'
+ '<configuration description="Runs some tests.">\n'
+ ' <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">\n'
+ ' <option name="test-file-name" value="foo.apk"/>\n'
+ ' </target_preparer>\n'
+ ' <test class="com.android.tradefed.testtype.AndroidJUnitTest">\n'
+ ' <option name="package" value="com.android.foo"/>\n'
+ ' <option name="runtime-hint" value="20s"/>\n'
+ ' </test>\n'
+ ' <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">\n'
+ ' <option name="enable" value="true"/>\n'
+ ' <option name="mainline-module-package-name" value="%s"/>\n'
+ ' </object>\n'
+ '</configuration>\n')
+
+ def test_testappinstallsetup(self):
+ doc = minidom.parseString(self.test_config % ("com.android.old.package.name"))
+
+ test_config_fixer.overwrite_mainline_module_package_name(doc, "com.android.new.package.name")
+ output = io.StringIO()
+ test_config_fixer.write_xml(output, doc)
+
+ # Only the mainline module package name should be updated. Format the xml
+ # with minidom first to avoid mismatches due to trivial reformatting.
+ expected = io.StringIO()
+ write_xml(expected, minidom.parseString(self.test_config % ("com.android.new.package.name")))
+ self.maxDiff = None
+ self.assertEqual(expected.getvalue(), output.getvalue())
+
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index d81635ebf..efb97be37 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -27,6 +27,11 @@ import (
// fixtureAddPlatformBootclasspathForBootclasspathFragment adds a platform_bootclasspath module that
// references the bootclasspath fragment.
func fixtureAddPlatformBootclasspathForBootclasspathFragment(apex, fragment string) android.FixturePreparer {
+ return fixtureAddPlatformBootclasspathForBootclasspathFragmentWithExtra(apex, fragment, "")
+}
+
+// fixtureAddPlatformBootclasspathForBootclasspathFragmentWithExtra is the same as above, but also adds extra fragments.
+func fixtureAddPlatformBootclasspathForBootclasspathFragmentWithExtra(apex, fragment, extraFragments string) android.FixturePreparer {
return android.GroupFixturePreparers(
// Add a platform_bootclasspath module.
android.FixtureAddTextFile("frameworks/base/boot/Android.bp", fmt.Sprintf(`
@@ -37,9 +42,10 @@ func fixtureAddPlatformBootclasspathForBootclasspathFragment(apex, fragment stri
apex: "%s",
module: "%s",
},
+ %s
],
}
- `, apex, fragment)),
+ `, apex, fragment, extraFragments)),
android.FixtureAddFile("frameworks/base/config/boot-profile.txt", nil),
android.FixtureAddFile("frameworks/base/config/boot-image-profile.txt", nil),
android.FixtureAddFile("build/soong/scripts/check_boot_jars/package_allowed_list.txt", nil),
@@ -79,9 +85,11 @@ func TestSnapshotWithBootclasspathFragment_ImageName(t *testing.T) {
}),
// Add a platform_bootclasspath that depends on the fragment.
- fixtureAddPlatformBootclasspathForBootclasspathFragment("com.android.art", "mybootclasspathfragment"),
+ fixtureAddPlatformBootclasspathForBootclasspathFragmentWithExtra(
+ "com.android.art", "mybootclasspathfragment", java.ApexBootJarFragmentsForPlatformBootclasspath),
java.PrepareForBootImageConfigTest,
+ java.PrepareApexBootJarConfigsAndModules,
android.FixtureWithRootAndroidBp(`
sdk {
name: "mysdk",
@@ -196,9 +204,15 @@ java_import {
snapshotTestChecker(checkSnapshotWithoutSource, func(t *testing.T, result *android.TestResult) {
// Make sure that the boot jars package check rule includes the dex jars retrieved from the prebuilt apex.
checkBootJarsPackageCheckRule(t, result,
- "out/soong/.intermediates/prebuilts/apex/com.android.art.deapexer/android_common/deapexer/javalib/core1.jar",
- "out/soong/.intermediates/prebuilts/apex/com.android.art.deapexer/android_common/deapexer/javalib/core2.jar",
- "out/soong/.intermediates/default/java/framework/android_common/aligned/framework.jar")
+ append(
+ []string{
+ "out/soong/.intermediates/prebuilts/apex/com.android.art.deapexer/android_common/deapexer/javalib/core1.jar",
+ "out/soong/.intermediates/prebuilts/apex/com.android.art.deapexer/android_common/deapexer/javalib/core2.jar",
+ "out/soong/.intermediates/default/java/framework/android_common/aligned/framework.jar",
+ },
+ java.ApexBootJarDexJarPaths...,
+ )...,
+ )
java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/snapshot/mybootclasspathfragment/android_common_com.android.art/meta_lic")
java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic")
}),
@@ -222,9 +236,15 @@ java_import {
// Make sure that the boot jars package check rule includes the dex jars created from the source.
checkBootJarsPackageCheckRule(t, result,
- "out/soong/.intermediates/core1/android_common_apex10000/aligned/core1.jar",
- "out/soong/.intermediates/core2/android_common_apex10000/aligned/core2.jar",
- "out/soong/.intermediates/default/java/framework/android_common/aligned/framework.jar")
+ append(
+ []string{
+ "out/soong/.intermediates/core1/android_common_apex10000/aligned/core1.jar",
+ "out/soong/.intermediates/core2/android_common_apex10000/aligned/core2.jar",
+ "out/soong/.intermediates/default/java/framework/android_common/aligned/framework.jar",
+ },
+ java.ApexBootJarDexJarPaths...,
+ )...,
+ )
}
// checkBootJarsPackageCheckRule checks that the supplied module is an input to the boot jars
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 2ade146b7..3a2ecc00c 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -33,7 +33,8 @@ var prepareForSdkTestWithJava = android.GroupFixturePreparers(
// Files needs by most of the tests.
android.MockFS{
- "Test.java": nil,
+ "Test.java": nil,
+ "art-profile": nil,
}.AddToFixture(),
)
diff --git a/sdk/systemserverclasspath_fragment_sdk_test.go b/sdk/systemserverclasspath_fragment_sdk_test.go
index 2a17cdc3a..66c44c843 100644
--- a/sdk/systemserverclasspath_fragment_sdk_test.go
+++ b/sdk/systemserverclasspath_fragment_sdk_test.go
@@ -62,6 +62,9 @@ func testSnapshotWithSystemServerClasspathFragment(t *testing.T, sdk string, tar
min_sdk_version: "2",
compile_dex: true,
permitted_packages: ["mylib"],
+ dex_preopt: {
+ profile: "art-profile",
+ },
}
java_sdk_library {
@@ -71,6 +74,9 @@ func testSnapshotWithSystemServerClasspathFragment(t *testing.T, sdk string, tar
shared_library: false,
public: {enabled: true},
min_sdk_version: "2",
+ dex_preopt: {
+ profile: "art-profile",
+ },
}
`),
).RunTest(t)
@@ -105,6 +111,9 @@ java_sdk_library_import {
visibility: ["//visibility:public"],
apex_available: ["myapex"],
shared_library: false,
+ dex_preopt: {
+ profile_guided: true,
+ },
public: {
jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
@@ -122,6 +131,9 @@ java_import {
jars: ["java_systemserver_libs/snapshot/jars/are/invalid/mylib.jar"],
min_sdk_version: "2",
permitted_packages: ["mylib"],
+ dex_preopt: {
+ profile_guided: true,
+ },
}
prebuilt_systemserverclasspath_fragment {
@@ -199,6 +211,54 @@ prebuilt_systemserverclasspath_fragment {
`)
})
+ t.Run("target-u", func(t *testing.T) {
+ testSnapshotWithSystemServerClasspathFragment(t, commonSdk, "UpsideDownCake", `
+// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+ name: "mysdklibrary",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["myapex"],
+ shared_library: false,
+ dex_preopt: {
+ profile_guided: true,
+ },
+ 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",
+ },
+}
+
+java_import {
+ name: "mylib",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["myapex"],
+ jars: ["java_systemserver_libs/snapshot/jars/are/invalid/mylib.jar"],
+ min_sdk_version: "2",
+ permitted_packages: ["mylib"],
+ dex_preopt: {
+ profile_guided: true,
+ },
+}
+
+prebuilt_systemserverclasspath_fragment {
+ name: "mysystemserverclasspathfragment",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["myapex"],
+ contents: [
+ "mylib",
+ "mysdklibrary",
+ ],
+}
+`)
+ })
+
t.Run("added-directly", func(t *testing.T) {
testSnapshotWithSystemServerClasspathFragment(t, commonSdk, `latest`, expectedLatestSnapshot)
})
diff --git a/sdk/update.go b/sdk/update.go
index f50439c3e..0820d62b8 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -565,7 +565,7 @@ func (m *moduleInfo) MarshalJSON() ([]byte, error) {
if m.deps != nil {
writeObjectPair("@deps", m.deps)
}
- for _, k := range android.SortedStringKeys(m.memberSpecific) {
+ for _, k := range android.SortedKeys(m.memberSpecific) {
v := m.memberSpecific[k]
writeObjectPair(k, v)
}
@@ -626,7 +626,7 @@ func (s *sdk) generateInfoData(ctx android.ModuleContext, memberVariantDeps []sd
getModuleInfo(memberVariantDep.variant)
}
- for _, memberName := range android.SortedStringKeys(name2Info) {
+ for _, memberName := range android.SortedKeys(name2Info) {
info := name2Info[memberName]
modules = append(modules, info)
}
@@ -1708,7 +1708,7 @@ func newArchSpecificInfo(ctx android.SdkMemberContext, archId archId, osType and
}
// Create the image variant info in a fixed order.
- for _, imageVariantName := range android.SortedStringKeys(variantsByImage) {
+ for _, imageVariantName := range android.SortedKeys(variantsByImage) {
variants := variantsByImage[imageVariantName]
archInfo.imageVariantInfos = append(archInfo.imageVariantInfos, newImageVariantSpecificInfo(ctx, imageVariantName, variantPropertiesFactory, variants))
}
diff --git a/starlark_fmt/format.go b/starlark_fmt/format.go
index 3e51fa14c..064fc2169 100644
--- a/starlark_fmt/format.go
+++ b/starlark_fmt/format.go
@@ -17,6 +17,7 @@ package starlark_fmt
import (
"fmt"
"sort"
+ "strconv"
"strings"
)
@@ -84,6 +85,16 @@ func PrintBoolDict(dict map[string]bool, indentLevel int) string {
return PrintDict(formattedValueDict, indentLevel)
}
+// PrintStringIntDict returns a Starlark-compatible string formatted as dictionary with
+// string keys and int values.
+func PrintStringIntDict(dict map[string]int, indentLevel int) string {
+ valDict := make(map[string]string, len(dict))
+ for k, v := range dict {
+ valDict[k] = strconv.Itoa(v)
+ }
+ return PrintDict(valDict, indentLevel)
+}
+
// PrintDict returns a starlark-compatible string containing a dictionary with string keys and
// values printed with no additional formatting.
func PrintDict(dict map[string]string, indentLevel int) string {
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index f3bad7378..fda5ca086 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -803,7 +803,6 @@ function test_bp2build_fails_fast {
setup
mkdir -p "a/${GENERATED_BUILD_FILE_NAME}"
- touch a/a.txt
cat > a/Android.bp <<EOF
filegroup {
name: "a",
@@ -813,7 +812,6 @@ filegroup {
EOF
mkdir -p "b/${GENERATED_BUILD_FILE_NAME}"
- touch b/b.txt
cat > b/Android.bp <<EOF
filegroup {
name: "b",
@@ -826,8 +824,8 @@ EOF
fail "Build should have failed"
fi
- grep -q "a/${GENERATED_BUILD_FILE_NAME}' exist" "$MOCK_TOP/errors" || fail "Error for a/${GENERATED_BUILD_FILE_NAME} not found"
- grep -q -v "b/${GENERATED_BUILD_FILE_NAME}' exist" "$MOCK_TOP/errors" || fail "Error for b/${GENERATED_BUILD_FILE_NAME} found but not expected"
+ # we should expect at least one error
+ grep -q -E "(a|b)/${GENERATED_BUILD_FILE_NAME}' exist" "$MOCK_TOP/errors" || fail "Error for ${GENERATED_BUILD_FILE_NAME} not found"
}
function test_bp2build_back_and_forth_null_build {
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 6477dac6e..1ff1b5bca 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -21,6 +21,68 @@ function test_bp2build_null_build {
fi
}
+# Tests that, if bp2build reruns due to a blueprint file changing, that
+# BUILD files whose contents are unchanged are not regenerated.
+function test_bp2build_unchanged {
+ setup
+
+ mkdir -p pkg
+ touch pkg/x.txt
+ cat > pkg/Android.bp <<'EOF'
+filegroup {
+ name: "x",
+ srcs: ["x.txt"],
+ bazel_module: {bp2build_available: true},
+ }
+EOF
+
+ run_soong bp2build
+ local -r buildfile_mtime1=$(stat -c "%y" out/soong/bp2build/pkg/BUILD.bazel)
+ local -r marker_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
+
+ # Force bp2build to rerun by updating the timestamp of a blueprint file.
+ touch pkg/Android.bp
+
+ run_soong bp2build
+ local -r buildfile_mtime2=$(stat -c "%y" out/soong/bp2build/pkg/BUILD.bazel)
+ local -r marker_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
+
+ if [[ "$marker_mtime1" == "$marker_mtime2" ]]; then
+ fail "Expected bp2build marker file to change"
+ fi
+ if [[ "$buildfile_mtime1" != "$buildfile_mtime2" ]]; then
+ fail "BUILD.bazel was updated even though contents are same"
+ fi
+}
+
+# Tests that blueprint files that are deleted are not present when the
+# bp2build tree is regenerated.
+function test_bp2build_deleted_blueprint {
+ setup
+
+ mkdir -p pkg
+ touch pkg/x.txt
+ cat > pkg/Android.bp <<'EOF'
+filegroup {
+ name: "x",
+ srcs: ["x.txt"],
+ bazel_module: {bp2build_available: true},
+ }
+EOF
+
+ run_soong bp2build
+ if [[ ! -e "./out/soong/bp2build/pkg/BUILD.bazel" ]]; then
+ fail "Expected pkg/BUILD.bazel to be generated"
+ fi
+
+ rm pkg/Android.bp
+
+ run_soong bp2build
+ if [[ -e "./out/soong/bp2build/pkg/BUILD.bazel" ]]; then
+ fail "Expected pkg/BUILD.bazel to be deleted"
+ fi
+}
+
function test_bp2build_null_build_with_globs {
setup
@@ -140,7 +202,7 @@ EOF
# NOTE: We don't actually use the extra BUILD file for anything here
run_bazel build --config=android --config=bp2build --config=ci //foo/...
- local the_answer_file="$(find -L bazel-out -name the_answer.txt)"
+ local -r the_answer_file="$(find -L bazel-out -name the_answer.txt)"
if [[ ! -f "${the_answer_file}" ]]; then
fail "Expected the_answer.txt to be generated, but was missing"
fi
@@ -156,6 +218,49 @@ function test_bp2build_generates_all_buildfiles {
eval "${_save_trap}"
}
+function test_bp2build_symlinks_files {
+ setup
+ mkdir -p foo
+ touch foo/BLANK1
+ touch foo/BLANK2
+ touch foo/F2D
+ touch foo/BUILD
+
+ run_soong bp2build
+
+ if [[ -e "./out/soong/workspace/foo/BUILD" ]]; then
+ fail "./out/soong/workspace/foo/BUILD should be omitted"
+ fi
+ for file in BLANK1 BLANK2 F2D
+ do
+ if [[ ! -L "./out/soong/workspace/foo/$file" ]]; then
+ fail "./out/soong/workspace/foo/$file should exist"
+ fi
+ done
+ local -r BLANK1_BEFORE=$(stat -c %y "./out/soong/workspace/foo/BLANK1")
+
+ rm foo/BLANK2
+ rm foo/F2D
+ mkdir foo/F2D
+ touch foo/F2D/BUILD
+
+ run_soong bp2build
+
+ if [[ -e "./out/soong/workspace/foo/BUILD" ]]; then
+ fail "./out/soong/workspace/foo/BUILD should be omitted"
+ fi
+ local -r BLANK1_AFTER=$(stat -c %y "./out/soong/workspace/foo/BLANK1")
+ if [[ "$BLANK1_AFTER" != "$BLANK1_BEFORE" ]]; then
+ fail "./out/soong/workspace/foo/BLANK1 should be untouched"
+ fi
+ if [[ -e "./out/soong/workspace/foo/BLANK2" ]]; then
+ fail "./out/soong/workspace/foo/BLANK2 should be removed"
+ fi
+ if [[ -L "./out/soong/workspace/foo/F2D" ]] || [[ ! -d "./out/soong/workspace/foo/F2D" ]]; then
+ fail "./out/soong/workspace/foo/F2D should be a dir"
+ fi
+}
+
function test_cc_correctness {
setup
diff --git a/tests/dcla_apex_comparison_test.sh b/tests/dcla_apex_comparison_test.sh
new file mode 100755
index 000000000..2ecb876fb
--- /dev/null
+++ b/tests/dcla_apex_comparison_test.sh
@@ -0,0 +1,138 @@
+#!/bin/bash
+
+# Copyright (C) 2023 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.
+
+set -euo pipefail
+
+# Soong/Bazel integration test to build the mainline modules in mixed build and
+# compare the DCLA libs extracted from those modules to ensure they are identical.
+
+if [ ! -e "build/make/core/Makefile" ]; then
+ echo "$0 must be run from the top of the Android source tree."
+ exit 1
+fi
+
+TARGET_PRODUCTS=(
+ module_arm64
+ module_x86_64
+)
+
+MODULES=(
+ # These modules depend on the DCLA libs
+ com.android.adbd
+ com.android.art
+ com.android.art.debug
+ com.android.art.testing
+ com.android.btservices
+ com.android.conscrypt
+ com.android.i18n
+ com.android.media
+ com.android.media.swcodec
+ com.android.resolv
+ com.android.runtime
+ com.android.tethering
+)
+
+DCLA_LIBS=(
+ libbase.so
+ libc++.so
+ libcrypto.so
+ libcutils.so
+)
+
+if [[ -z ${OUT_DIR+x} ]]; then
+ OUT_DIR="out"
+fi
+
+if [[ -z ${ANDROID_HOST_OUT+x} ]]; then
+ export ANDROID_HOST_OUT="out/host/linux-x86"
+fi
+
+######################
+# Build deapexer and debugfs
+######################
+DEAPEXER="${ANDROID_HOST_OUT}/bin/deapexer"
+DEBUGFS="${ANDROID_HOST_OUT}/bin/debugfs"
+if [[ ! -f "${DEAPEXER}" ]] || [[ ! -f "${DEBUGFS}" ]]; then
+ build/soong/soong_ui.bash --make-mode --skip-soong-tests deapexer debugfs
+fi
+
+DEAPEXER="${DEAPEXER} --debugfs_path=${DEBUGFS}"
+
+############
+# Test Setup
+############
+OUTPUT_DIR="$(mktemp -d tmp.XXXXXX)"
+
+function cleanup {
+ rm -rf "${OUTPUT_DIR}"
+}
+trap cleanup EXIT
+
+#######
+# Tests
+#######
+
+function extract_dcla_libs() {
+ local product=$1; shift
+ for module in "${MODULES[@]}"; do
+ local apex="${OUTPUT_DIR}/${product}/${module}.apex"
+ local extract_dir="${OUTPUT_DIR}/${product}/${module}/extract"
+
+ $DEAPEXER extract "${apex}" "${extract_dir}"
+ done
+}
+
+function compare_dcla_libs() {
+ local product=$1; shift
+
+ for lib in "${DCLA_LIBS[@]}"; do
+ for arch in lib lib64; do
+ local prev_sha=""
+ for module in "${MODULES[@]}"; do
+ local file="${OUTPUT_DIR}/${product}/${module}/extract/${arch}/${lib}"
+ if [[ ! -f "${file}" ]]; then
+ # not all libs are present in a module
+ echo "file doesn't exist: ${file}"
+ continue
+ fi
+ sha=$(sha1sum ${file})
+ sha="${sha% *}"
+ if [ "${prev_sha}" == "" ]; then
+ prev_sha="${sha}"
+ elif [ "${sha}" != "${prev_sha}" ]; then
+ echo "Test failed, ${lib} has different hash value"
+ exit 1
+ fi
+ done
+ done
+ done
+}
+
+export UNBUNDLED_BUILD_SDKS_FROM_SOURCE=true # don't rely on prebuilts
+export TARGET_BUILD_APPS="${MODULES[@]}"
+for product in "${TARGET_PRODUCTS[@]}"; do
+ ###########
+ # Build the mainline modules
+ ###########
+ packages/modules/common/build/build_unbundled_mainline_module.sh \
+ --product "${product}" \
+ --dist_dir "${OUTPUT_DIR}/${product}"
+
+ extract_dcla_libs "${product}"
+ compare_dcla_libs "${product}"
+done
+
+echo "Test passed"
diff --git a/tests/persistent_bazel_test.sh b/tests/persistent_bazel_test.sh
new file mode 100755
index 000000000..4e2982a39
--- /dev/null
+++ b/tests/persistent_bazel_test.sh
@@ -0,0 +1,83 @@
+#!/bin/bash -eu
+
+# Copyright (C) 2023 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.
+
+set -o pipefail
+
+source "$(dirname "$0")/lib.sh"
+
+# This test verifies that adding USE_PERSISTENT_BAZEL creates a Bazel process
+# that outlasts the build process.
+# This test should only be run in sandboxed environments (because this test
+# verifies a Bazel process using global process list, and may spawn lingering
+# Bazel processes).
+function test_persistent_bazel {
+ setup
+
+ # Ensure no existing Bazel process.
+ if [[ -e out/bazel/output/server/server.pid.txt ]]; then
+ kill $(cat out/bazel/output/server/server.pid.txt) 2>/dev/null || true
+ if kill -0 $(cat out/bazel/output/server/server.pid.txt) 2>/dev/null ; then
+ fail "Error killing pre-setup bazel"
+ fi
+ fi
+
+ USE_PERSISTENT_BAZEL=1 run_soong nothing
+
+ if ! kill -0 $(cat out/bazel/output/server/server.pid.txt) 2>/dev/null ; then
+ fail "Persistent bazel process expected, but not found after first build"
+ fi
+ BAZEL_PID=$(cat out/bazel/output/server/server.pid.txt)
+
+ USE_PERSISTENT_BAZEL=1 run_soong nothing
+
+ if ! kill -0 $BAZEL_PID 2>/dev/null ; then
+ fail "Bazel pid $BAZEL_PID was killed after second build"
+ fi
+
+ kill $BAZEL_PID 2>/dev/null
+ if ! kill -0 $BAZEL_PID 2>/dev/null ; then
+ fail "Error killing bazel on shutdown"
+ fi
+}
+
+# Verifies that USE_PERSISTENT_BAZEL mode operates as expected in the event
+# that there are Bazel failures.
+function test_bazel_failure {
+ setup
+
+ # Ensure no existing Bazel process.
+ if [[ -e out/bazel/output/server/server.pid.txt ]]; then
+ kill $(cat out/bazel/output/server/server.pid.txt) 2>/dev/null || true
+ if kill -0 $(cat out/bazel/output/server/server.pid.txt) 2>/dev/null ; then
+ fail "Error killing pre-setup bazel"
+ fi
+ fi
+
+ # Introduce a syntax error in a BUILD file which is used in every build
+ # (Note this is a BUILD file which is copied as part of test setup, so this
+ # has no effect on sources outside of this test.
+ rm -rf build/bazel/rules
+
+ USE_PERSISTENT_BAZEL=1 run_soong nothing 1>out/failurelog.txt 2>&1 && fail "Expected build failure" || true
+
+ if ! grep -sq "'build/bazel/rules' is not a package" out/failurelog.txt ; then
+ fail "Expected error to contain 'build/bazel/rules' is not a package, instead got:\n$(cat out/failurelog.txt)"
+ fi
+
+ kill $(cat out/bazel/output/server/server.pid.txt) 2>/dev/null || true
+}
+
+scan_and_run_tests
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index eb76a461f..a91ccf465 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -7,6 +7,7 @@ TOP="$(readlink -f "$(dirname "$0")"/../../..)"
"$TOP/build/soong/tests/bootstrap_test.sh"
"$TOP/build/soong/tests/mixed_mode_test.sh"
"$TOP/build/soong/tests/bp2build_bazel_test.sh"
+"$TOP/build/soong/tests/persistent_bazel_test.sh"
"$TOP/build/soong/tests/soong_test.sh"
"$TOP/build/bazel/ci/rbc_regression_test.sh" aosp_arm64-userdebug
@@ -14,7 +15,7 @@ TOP="$(readlink -f "$(dirname "$0")"/../../..)"
# mock client.
"$TOP/build/soong/tests/apex_comparison_tests.sh"
"$TOP/build/soong/tests/apex_comparison_tests.sh" "module_arm64only"
-
+"$TOP/build/soong/tests/dcla_apex_comparison_test.sh"
"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh"
"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_arm" "armv7-a"
-"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_cf_arm64_phone" "armv8-a" "cortex-a53" \ No newline at end of file
+"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_cf_arm64_phone" "armv8-a" "cortex-a53"
diff --git a/ui/build/config.go b/ui/build/config.go
index cb7fe1e89..b5ee44064 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -369,6 +369,7 @@ func NewConfig(ctx Context, args ...string) Config {
"CDPATH",
"DISPLAY",
"GREP_OPTIONS",
+ "JAVAC",
"NDK_ROOT",
"POSIXLY_CORRECT",
@@ -1567,6 +1568,10 @@ func (c *configImpl) IsBazelMixedBuildForceDisabled() bool {
return c.Environment().IsEnvTrue("BUILD_BROKEN_DISABLE_BAZEL")
}
+func (c *configImpl) IsPersistentBazelEnabled() bool {
+ return c.Environment().IsEnvTrue("USE_PERSISTENT_BAZEL")
+}
+
func (c *configImpl) BazelModulesForceEnabledByFlag() string {
return c.bazelForceEnabledModules
}
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 1e3e54764..a9c298f57 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -84,6 +84,14 @@ func dumpMakeVars(ctx Context, config Config, goals, vars []string, write_soong_
ctx.BeginTrace(metrics.RunKati, "dumpvars")
defer ctx.EndTrace()
+ tool := ctx.Status.StartTool()
+ if write_soong_vars {
+ // only print this when write_soong_vars is true so that it's not printed when using
+ // the get_build_var command.
+ tool.Status("Running product configuration...")
+ }
+ defer tool.Finish()
+
cmd := Command(ctx, config, "dumpvars",
config.PrebuiltBuildTool("ckati"),
"-f", "build/make/core/config.mk",
@@ -108,7 +116,7 @@ func dumpMakeVars(ctx Context, config Config, goals, vars []string, write_soong_
}
cmd.StartOrFatal()
// TODO: error out when Stderr contains any content
- status.KatiReader(ctx.Status.StartTool(), pipe)
+ status.KatiReader(tool, pipe)
cmd.WaitOrFatal()
ret := make(map[string]string, len(vars))
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index dab1a9b58..28f3c3806 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -23,10 +23,16 @@ import (
"strings"
"time"
+ "android/soong/shared"
"android/soong/ui/metrics"
"android/soong/ui/status"
)
+const (
+ // File containing the environment state when ninja is executed
+ ninjaEnvFileName = "ninja.environment"
+)
+
// Constructs and runs the Ninja command line with a restricted set of
// environment variables. It's important to restrict the environment Ninja runs
// for hermeticity reasons, and to avoid spurious rebuilds.
@@ -186,6 +192,21 @@ func runNinjaForBuild(ctx Context, config Config) {
ctx.Verbosef(" %s", envVar)
}
+ // Write the env vars available during ninja execution to a file
+ ninjaEnvVars := cmd.Environment.AsMap()
+ data, err := shared.EnvFileContents(ninjaEnvVars)
+ if err != nil {
+ ctx.Panicf("Could not parse environment variables for ninja run %s", err)
+ }
+ // Write the file in every single run. This is fine because
+ // 1. It is not a dep of Soong analysis, so will not retrigger Soong analysis.
+ // 2. Is is fairly lightweight (~1Kb)
+ ninjaEnvVarsFile := shared.JoinPath(config.SoongOutDir(), ninjaEnvFileName)
+ err = os.WriteFile(ninjaEnvVarsFile, data, 0666)
+ if err != nil {
+ ctx.Panicf("Could not write ninja environment file %s", err)
+ }
+
// Poll the Ninja log for updates regularly based on the heartbeat
// frequency. If it isn't updated enough, then we want to surface the
// possibility that Ninja is stuck, to the user.
diff --git a/ui/build/path.go b/ui/build/path.go
index 86e61c0da..29128d81f 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -109,6 +109,15 @@ func SetupLitePath(ctx Context, config Config, tmpDir string) {
prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
+ if value, _ := config.Environment().Get("BUILD_BROKEN_PYTHON_IS_PYTHON2"); value == "true" {
+ py2Path, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86/py2")
+ if info, err := os.Stat(py2Path); err == nil && info.IsDir() {
+ myPath = py2Path + string(os.PathListSeparator) + myPath
+ }
+ } else if value != "" {
+ ctx.Fatalf("BUILD_BROKEN_PYTHON_IS_PYTHON2 can only be set to 'true' or an empty string, but got %s\n", value)
+ }
+
// Set $PATH to be the directories containing the host tool symlinks, and
// the prebuilts directory for the current host OS.
config.Environment().Set("PATH", myPath)
@@ -244,6 +253,15 @@ func SetupPath(ctx Context, config Config) {
prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
+ if value, _ := config.Environment().Get("BUILD_BROKEN_PYTHON_IS_PYTHON2"); value == "true" {
+ py2Path, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86/py2")
+ if info, err := os.Stat(py2Path); err == nil && info.IsDir() {
+ myPath = py2Path + string(os.PathListSeparator) + myPath
+ }
+ } else if value != "" {
+ ctx.Fatalf("BUILD_BROKEN_PYTHON_IS_PYTHON2 can only be set to 'true' or an empty string, but got %s\n", value)
+ }
+
// Replace the $PATH variable with the path_interposer symlinks, and
// checked-in prebuilts.
config.Environment().Set("PATH", myPath)
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 3c844c105..1d1721623 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -100,6 +100,8 @@ func startRBE(ctx Context, config Config) {
ctx.BeginTrace(metrics.RunSetupTool, "rbe_bootstrap")
defer ctx.EndTrace()
+ ctx.Status.Status("Starting rbe...")
+
if u := ulimitOrFatal(ctx, config, "-u"); u < rbeLeastNProcs {
ctx.Fatalf("max user processes is insufficient: %d; want >= %d.\n", u, rbeLeastNProcs)
}
@@ -180,6 +182,8 @@ func DumpRBEMetrics(ctx Context, config Config, filename string) {
return
}
+ ctx.Status.Status("Dumping rbe metrics...")
+
outputDir := config.rbeProxyLogsDir()
if outputDir == "" {
ctx.Fatal("RBE output dir variable not defined. Aborting metrics dumping.")
diff --git a/ui/build/soong.go b/ui/build/soong.go
index e6543ec17..a5a3263bb 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -21,6 +21,7 @@ import (
"strconv"
"strings"
+ "android/soong/bazel"
"android/soong/ui/metrics"
"android/soong/ui/status"
@@ -268,6 +269,9 @@ func bootstrapBlueprint(ctx Context, config Config) {
if config.bazelStagingMode {
mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-mode-staging")
}
+ if config.IsPersistentBazelEnabled() {
+ mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--use-bazel-proxy")
+ }
if len(config.bazelForceEnabledModules) > 0 {
mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-force-enabled-modules="+config.bazelForceEnabledModules)
}
@@ -497,6 +501,12 @@ func runSoong(ctx Context, config Config) {
ctx.BeginTrace(metrics.RunSoong, name)
defer ctx.EndTrace()
+ if config.IsPersistentBazelEnabled() {
+ bazelProxy := bazel.NewProxyServer(ctx.Logger, config.OutDir(), filepath.Join(config.SoongOutDir(), "workspace"))
+ bazelProxy.Start()
+ defer bazelProxy.Close()
+ }
+
fifo := filepath.Join(config.OutDir(), ".ninja_fifo")
nr := status.NewNinjaReader(ctx, ctx.Status.StartTool(), fifo)
defer nr.Close()