Merge "Allow SCS for riscv64 too."
diff --git a/OWNERS b/OWNERS
index e18eea1..964e27a 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 @@
jingwen@google.com
# EMEA
-hansson@google.com #{LAST_RESORT_SUGGESTION}
lberki@google.com
-paulduffin@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/android/Android.bp b/android/Android.bp
index 29a88f2..641c438 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -111,6 +111,7 @@
"depset_test.go",
"deptag_test.go",
"expand_test.go",
+ "filegroup_test.go",
"fixture_test.go",
"gen_notice_test.go",
"license_kind_test.go",
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 1353293..2917931 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -125,6 +125,7 @@
"external/eigen": Bp2BuildDefaultTrueRecursively,
"external/erofs-utils": Bp2BuildDefaultTrueRecursively,
"external/error_prone": Bp2BuildDefaultTrueRecursively,
+ "external/escapevelocity": Bp2BuildDefaultTrueRecursively,
"external/expat": Bp2BuildDefaultTrueRecursively,
"external/f2fs-tools": Bp2BuildDefaultTrue,
"external/flac": Bp2BuildDefaultTrueRecursively,
@@ -143,7 +144,10 @@
"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,
@@ -195,7 +199,9 @@
"frameworks/base/startop/apps/test": Bp2BuildDefaultTrue,
"frameworks/base/tests/appwidgets/AppWidgetHostTest": Bp2BuildDefaultTrueRecursively,
"frameworks/base/tools/aapt2": Bp2BuildDefaultTrue,
+ "frameworks/base/tools/codegen": Bp2BuildDefaultTrueRecursively,
"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,
@@ -213,6 +219,8 @@
"hardware/interfaces": Bp2BuildDefaultTrue,
"hardware/interfaces/audio/aidl": Bp2BuildDefaultTrue,
+ "hardware/interfaces/audio/aidl/common": Bp2BuildDefaultTrue,
+ "hardware/interfaces/bufferpool/aidl": Bp2BuildDefaultTrue,
"hardware/interfaces/common/aidl": Bp2BuildDefaultTrue,
"hardware/interfaces/common/fmq/aidl": Bp2BuildDefaultTrue,
"hardware/interfaces/configstore/1.0": Bp2BuildDefaultTrue,
@@ -254,29 +262,32 @@
"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 +356,8 @@
"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,18 +381,16 @@
"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,
// this BUILD file is globbed by //external/icu/icu4c/source:icu4c_test_data's "data/**/*".
"external/icu/icu4c/source/data/unidata/norm2":/* recursive = */ false,
- "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,
@@ -390,7 +400,7 @@
"prebuilts/clang-tools":/* recursive = */ true,
"prebuilts/gcc":/* recursive = */ true,
"prebuilts/build-tools":/* recursive = */ true,
- "prebuilts/jdk/jdk11":/* recursive = */ false,
+ "prebuilts/jdk/jdk17":/* recursive = */ true,
"prebuilts/misc":/* recursive = */ false, // not recursive because we need bp2build converted build files in prebuilts/misc/common/asm
"prebuilts/sdk":/* recursive = */ false,
"prebuilts/sdk/tools":/* recursive = */ false,
@@ -679,16 +689,43 @@
// kotlin srcs in android_library
"renderscript_toolkit",
+
+ //kotlin srcs in android_binary
+ "MusicKotlin",
+
+ // checked in current.txt for merged_txts
+ "non-updatable-current.txt",
+ "non-updatable-system-current.txt",
+ "non-updatable-module-lib-current.txt",
+ "non-updatable-system-server-current.txt",
+
+ // for api_fingerprint.txt generation
+ "api_fingerprint",
+
+ // allowlisting for kotlinx_coroutines
+ "kotlinx_coroutines",
+ "annotations",
+ "kotlinx-coroutines-android-annotation-stubs",
+
+ // for building com.android.neuralnetworks
+ "libimapper_stablec",
+ "libimapper_providerutils",
+
+ // min_sdk_version in android_app
+ "CtsShimUpgrade",
+ "fake-framework",
}
Bp2buildModuleTypeAlwaysConvertList = []string{
"aidl_interface_headers",
+ "bpf",
+ "combined_apis",
"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
@@ -836,6 +873,9 @@
"android.hardware.health-translate-java",
// cc_test related.
+ // b/274164834 "Could not open Configuration file test.cfg"
+ "svcenc", "svcdec",
+
// Failing host cc_tests
"memunreachable_unit_test",
"libprocinfo_test",
@@ -1326,6 +1366,9 @@
// uses glob in $(locations)
"libc_musl_sysroot",
+
+ // TODO(b/266459895): depends on libunwindstack
+ "libutils_test",
}
MixedBuildsDisabledList = []string{
@@ -1399,8 +1442,19 @@
// Bazel prod-mode allowlist. Modules in this list are built by Bazel
// in either prod mode or staging mode.
ProdMixedBuildsEnabledList = []string{
+ // M5: tzdata launch
"com.android.tzdata",
"test1_com.android.tzdata",
+ // M7: adbd launch
+ "com.android.adbd",
+ "test_com.android.adbd",
+ "adbd_test",
+ "adb_crypto_test",
+ "adb_pairing_auth_test",
+ "adb_pairing_connection_test",
+ "adb_tls_connection_test",
+ // M9: mixed builds for mainline trains launch
+ "api_fingerprint",
}
// Staging-mode allowlist. Modules in this list are only built
@@ -1408,12 +1462,21 @@
// 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{
+ "libbase",
+ "libc++",
+ "libcrypto",
+ "libcutils",
}
+
+ // These should be the libs that are included by the apexes in the StagingMixedBuildsEnabledList
+ StagingDclaMixedBuildsEnabledList = []string{}
+
+ // 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 6346401..aa411d1 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -501,6 +501,7 @@
// 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 @@
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))
@@ -547,6 +548,7 @@
a.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...)
a.AddStrings("LOCAL_HOST_REQUIRED_MODULES", a.Host_required...)
a.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", a.Target_required...)
+ a.AddStrings("LOCAL_SOONG_MODULE_TYPE", ctx.ModuleType(amod))
// If the install rule was generated by Soong tell Make about it.
if len(base.katiInstalls) > 0 {
diff --git a/android/apex.go b/android/apex.go
index 3c945ae..358818f 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -817,7 +817,7 @@
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 bf7b317..9440ee9 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -225,6 +225,8 @@
// ApiLevelFromUserWithConfig implements ApiLevelFromUser, see comments for
// ApiLevelFromUser for more details.
func ApiLevelFromUserWithConfig(config Config, raw string) (ApiLevel, error) {
+ // This logic is replicated in starlark, if changing logic here update starlark code too
+ // https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/common/api.bzl;l=42;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
if raw == "" {
panic("API level string must be non-empty")
}
@@ -302,31 +304,37 @@
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 {
+ // This logic is replicated in starlark, if changing logic here update starlark code too
+ // https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/common/api.bzl;l=30;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
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 +357,12 @@
var apiLevelsMapKey = NewOnceKey("ApiLevelsMap")
+// ApiLevelsMap has entries for preview API levels
func GetApiLevelsMap(config Config) map[string]int {
+ // This logic is replicated in starlark, if changing logic here update starlark code too
+ // https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/common/api.bzl;l=23;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
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 +377,11 @@
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/arch.go b/android/arch.go
index 6acf9cf..4b4691b 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -1694,6 +1694,7 @@
return []archConfig{
{"arm64", "armv8-a-branchprot", "", []string{"arm64-v8a"}},
{"arm", "armv7-a-neon", "", []string{"armeabi-v7a"}},
+ {"riscv64", "", "", []string{"riscv64"}},
{"x86_64", "", "", []string{"x86_64"}},
{"x86", "", "", []string{"x86"}},
}
diff --git a/android/arch_list.go b/android/arch_list.go
index 578904c..ab644a4 100644
--- a/android/arch_list.go
+++ b/android/arch_list.go
@@ -26,6 +26,7 @@
"armv8-a-branchprot",
"armv8-2a",
"armv8-2a-dotprod",
+ "armv9-a",
},
X86: {
"amberlake",
@@ -71,6 +72,7 @@
"cortex-a8",
"cortex-a9",
"cortex-a15",
+ "cortex-a32",
"cortex-a53",
"cortex-a53.a57",
"cortex-a55",
@@ -148,6 +150,9 @@
"armv8-2a-dotprod": {
"dotprod",
},
+ "armv9-a": {
+ "dotprod",
+ },
},
X86: {
"amberlake": {
diff --git a/android/bazel.go b/android/bazel.go
index 10e9251..782632b 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -352,11 +352,14 @@
// 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.
+ ctx.Os() != LinuxBionic && // Linux Bionic 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 +529,15 @@
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 123cc60..44dc055 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -29,8 +29,10 @@
"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 @@
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 @@
// 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 @@
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 @@
// 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 {
@@ -192,7 +241,7 @@
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
@@ -205,6 +254,8 @@
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
@@ -228,10 +279,16 @@
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) {
@@ -242,10 +299,14 @@
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
}
@@ -274,18 +335,22 @@
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 {
@@ -294,6 +359,26 @@
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()
@@ -392,7 +477,7 @@
panic("implement me")
}
-func (n noopBazelContext) InvokeBazel(_ Config, _ *Context) error {
+func (n noopBazelContext) InvokeBazel(_ Config, _ invokeBazelContext) error {
panic("unimplemented")
}
@@ -400,26 +485,31 @@
return ""
}
-func (n noopBazelContext) IsModuleNameAllowed(_ string) bool {
+func (n noopBazelContext) IsModuleNameAllowed(_ string, _ bool) bool {
return false
}
-func (m noopBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
- return []bazel.BuildStatement{}
+func (n noopBazelContext) IsModuleDclaAllowed(_ string) bool {
+ return false
+}
+
+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:
@@ -507,15 +597,24 @@
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,
- 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
}
@@ -523,16 +622,24 @@
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" {
@@ -558,7 +665,7 @@
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, " "))
@@ -570,32 +677,57 @@
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),
@@ -604,15 +736,6 @@
// TODO(asmundak): is it needed in every build?
"--profile=" + shared.BazelMetricsFilename(paths, runName),
- // Set default platforms to canonicalized values for mixed builds requests.
- // If these are set in the bazelrc, they will have values that are
- // non-canonicalized to @sourceroot labels, and thus be invalid when
- // referenced from the buildroot.
- //
- // The actual platform values here may be overridden by configuration
- // transitions from the buildroot.
- fmt.Sprintf("--extra_toolchains=%s", "//prebuilts/clang/host/linux-x86:all"),
-
// We don't need to set --host_platforms because it's set in bazelrc files
// that the bazel shell script wrapper passes
@@ -639,6 +762,13 @@
// 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
@@ -657,21 +787,37 @@
#####################################################
# 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",
],
)
@@ -681,9 +827,11 @@
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"),
},
)
@@ -742,6 +890,8 @@
config_node(name = "%s",
arch = "%s",
os = "%s",
+ within_apex = %s,
+ apex_sdk_version = "%s",
deps = [%s],
testonly = True, # Unblocks testonly deps.
)
@@ -768,15 +918,28 @@
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 ")))
@@ -837,31 +1000,6 @@
formatString := `
# This file is generated by soong_build. Do not edit.
-# a drop-in replacement for json.encode(), not available in cquery environment
-# TODO(cparsons): bring json module in and remove this function
-def json_encode(input):
- # Avoiding recursion by limiting
- # - a dict to contain anything except a dict
- # - a list to contain only primitives
- def encode_primitive(p):
- t = type(p)
- if t == "string" or t == "int":
- return repr(p)
- fail("unsupported value '%s' of type '%s'" % (p, type(p)))
-
- def encode_list(list):
- return "[%s]" % ", ".join([encode_primitive(item) for item in list])
-
- def encode_list_or_primitive(v):
- return encode_list(v) if type(v) == "list" else encode_primitive(v)
-
- if type(input) == "dict":
- # TODO(juu): the result is read line by line so can't use '\n' yet
- kv_pairs = [("%s: %s" % (encode_primitive(k), encode_list_or_primitive(v))) for (k, v) in input.items()]
- return "{ %s }" % ", ".join(kv_pairs)
- else:
- return encode_list_or_primitive(input)
-
{LABEL_REGISTRATION_MAP_SECTION}
{FUNCTION_DEF_SECTION}
@@ -872,6 +1010,7 @@
# 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.
@@ -888,15 +1027,26 @@
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)
@@ -953,11 +1103,10 @@
// 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 {
@@ -965,13 +1114,13 @@
}
}
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
}
@@ -980,11 +1129,10 @@
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) {
@@ -1007,9 +1155,13 @@
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
}
@@ -1043,11 +1195,10 @@
return nil
}
-func (context *mixedBuildBazelContext) runAquery(config Config, ctx *Context) error {
- if ctx != nil {
- ctx.EventHandler.Begin("aquery")
- defer ctx.EventHandler.End("aquery")
- }
+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
@@ -1072,28 +1223,27 @@
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
}
@@ -1161,6 +1311,11 @@
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)
@@ -1205,7 +1360,7 @@
}
// 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))
@@ -1285,7 +1440,16 @@
// 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 {
@@ -1296,6 +1460,29 @@
}
}
+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 d971802..c67d7fb 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -11,33 +11,57 @@
"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 @@
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)
}
@@ -171,14 +195,18 @@
func TestBazelRequestsSorted(t *testing.T) {
bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
- bazelContext.QueueBazelRequest("zzz", cquery.GetOutputFiles, configKey{"arm64_armv8-a", Android})
- bazelContext.QueueBazelRequest("ccc", cquery.GetApexInfo, configKey{"arm64_armv8-a", Android})
- bazelContext.QueueBazelRequest("duplicate", cquery.GetOutputFiles, configKey{"arm64_armv8-a", Android})
- bazelContext.QueueBazelRequest("duplicate", cquery.GetOutputFiles, configKey{"arm64_armv8-a", Android})
- bazelContext.QueueBazelRequest("xxx", cquery.GetOutputFiles, configKey{"arm64_armv8-a", Linux})
- bazelContext.QueueBazelRequest("aaa", cquery.GetOutputFiles, configKey{"arm64_armv8-a", Android})
- bazelContext.QueueBazelRequest("aaa", cquery.GetOutputFiles, configKey{"otherarch", Android})
- bazelContext.QueueBazelRequest("bbb", cquery.GetOutputFiles, configKey{"otherarch", Android})
+ 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))
@@ -194,10 +222,56 @@
}
}
+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)
}
diff --git a/android/config.go b/android/config.go
index c305114..292fcf2 100644
--- a/android/config.go
+++ b/android/config.go
@@ -83,10 +83,14 @@
ModuleActionsFile string
DocFile string
+ MultitreeBuild bool
+
BazelMode bool
BazelModeDev bool
BazelModeStaging bool
BazelForceEnabledModules string
+
+ UseBazelProxy bool
}
// Build modes that soong_build can run as.
@@ -227,6 +231,10 @@
Bp2buildPackageConfig Bp2BuildConversionAllowlist
Bp2buildSoongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions
+ // If MultitreeBuild is true then this is one inner tree of a multitree
+ // build directed by the multitree orchestrator.
+ MultitreeBuild bool
+
// If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error
// in tests when a path doesn't exist.
TestAllowNonExistentPaths bool
@@ -251,6 +259,10 @@
// 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 +409,13 @@
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 +454,9 @@
mixedBuildDisabledModules: make(map[string]struct{}),
mixedBuildEnabledModules: make(map[string]struct{}),
bazelForceEnabledModules: make(map[string]struct{}),
+
+ MultitreeBuild: cmdArgs.MultitreeBuild,
+ UseBazelProxy: cmdArgs.UseBazelProxy,
}
config.deviceConfig = &deviceConfig{
@@ -725,10 +742,6 @@
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 {
@@ -877,6 +890,8 @@
// DefaultAppTargetSdk returns the API level that platform apps are targeting.
// This converts a codename to the exact ApiLevel it represents.
func (c *config) DefaultAppTargetSdk(ctx EarlyModuleContext) ApiLevel {
+ // This logic is replicated in starlark, if changing logic here update starlark code too
+ // https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/common/api.bzl;l=72;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
if Bool(c.productVariables.Platform_sdk_final) {
return c.PlatformSdkVersion()
}
@@ -1751,6 +1766,10 @@
return c.config.productVariables.BuildBrokenTrebleSyspropNeverallow
}
+func (c *deviceConfig) BuildBrokenUsesSoongPython2Modules() bool {
+ return c.config.productVariables.BuildBrokenUsesSoongPython2Modules
+}
+
func (c *deviceConfig) BuildDebugfsRestrictionsEnabled() bool {
return c.config.productVariables.BuildDebugfsRestrictionsEnabled
}
@@ -1829,3 +1848,14 @@
c.mixedBuildDisabledModules[moduleName] = struct{}{}
}
}
+
+// ApiSurfaces directory returns the source path inside the api_surfaces repo
+// (relative to workspace root).
+func (c *config) ApiSurfacesDir(s ApiSurface, version string) string {
+ return filepath.Join(
+ "build",
+ "bazel",
+ "api_surfaces",
+ s.String(),
+ version)
+}
diff --git a/android/config_bp2build.go b/android/config_bp2build.go
index 2beeb51..830890d 100644
--- a/android/config_bp2build.go
+++ b/android/config_bp2build.go
@@ -95,6 +95,15 @@
return ev.pctx.VariableConfigMethod(name, method)
}
+func (ev ExportedVariables) ExportStringStaticVariableWithEnvOverride(name, envVar, defaultVal string) {
+ ev.ExportVariableConfigMethod(name, func(config Config) string {
+ if override := config.Getenv(envVar); override != "" {
+ return override
+ }
+ return defaultVal
+ })
+}
+
// ExportSourcePathVariable declares a static "source path" variable and exports
// it to Bazel's toolchain.
func (ev ExportedVariables) ExportSourcePathVariable(name string, value string) {
diff --git a/android/defaults.go b/android/defaults.go
index 7906e94..31d6014 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -15,8 +15,6 @@
package android
import (
- "bytes"
- "fmt"
"reflect"
"github.com/google/blueprint"
@@ -55,7 +53,7 @@
d.hook = hook
}
-func (d *DefaultableModuleBase) callHookIfAvailable(ctx DefaultableHookContext) {
+func (d *DefaultableModuleBase) CallHookIfAvailable(ctx DefaultableHookContext) {
if d.hook != nil {
d.hook(ctx)
}
@@ -69,11 +67,9 @@
// Set the property structures into which defaults will be added.
setProperties(props []interface{}, variableProperties interface{})
- // Apply defaults from the supplied DefaultsModule to the property structures supplied to
+ // Apply defaults from the supplied Defaults to the property structures supplied to
// setProperties(...).
- applyDefaults(TopDownMutatorContext, []DefaultsModule)
-
- applySingleDefaultsWithTracker(EarlyModuleContext, DefaultsModule, defaultsTrackerFunc)
+ applyDefaults(TopDownMutatorContext, []Defaults)
// Set the hook to be called after any defaults have been applied.
//
@@ -82,7 +78,7 @@
SetDefaultableHook(hook DefaultableHook)
// Call the hook if specified.
- callHookIfAvailable(context DefaultableHookContext)
+ CallHookIfAvailable(context DefaultableHookContext)
}
type DefaultableModule interface {
@@ -119,23 +115,9 @@
Defaults_visibility []string
}
-// AdditionalDefaultsProperties contains properties of defaults modules which
-// can have other defaults applied.
-type AdditionalDefaultsProperties struct {
-
- // The list of properties set by the default whose values must not be changed by any module that
- // applies these defaults. It is an error if a property is not supported by the defaults module or
- // has not been set to a non-zero value. If this contains "*" then that must be the only entry in
- // which case all properties that are set on this defaults will be protected (except the
- // protected_properties and visibility.
- Protected_properties []string
-}
-
type DefaultsModuleBase struct {
DefaultableModuleBase
- defaultsProperties AdditionalDefaultsProperties
-
// Included to support setting bazel_module.label for multiple Soong modules to the same Bazel
// target. This is primarily useful for modules that were architecture specific and instead are
// handled in Bazel as a select().
@@ -169,18 +151,6 @@
// DefaultsModuleBase will type-assert to the Defaults interface.
isDefaults() bool
- // additionalDefaultableProperties returns additional properties provided by the defaults which
- // can themselves have defaults applied.
- additionalDefaultableProperties() []interface{}
-
- // protectedProperties returns the names of the properties whose values cannot be changed by a
- // module that applies these defaults.
- protectedProperties() []string
-
- // setProtectedProperties sets the names of the properties whose values cannot be changed by a
- // module that applies these defaults.
- setProtectedProperties(protectedProperties []string)
-
// Get the structures containing the properties for which defaults can be provided.
properties() []interface{}
@@ -197,18 +167,6 @@
Bazelable
}
-func (d *DefaultsModuleBase) additionalDefaultableProperties() []interface{} {
- return []interface{}{&d.defaultsProperties}
-}
-
-func (d *DefaultsModuleBase) protectedProperties() []string {
- return d.defaultsProperties.Protected_properties
-}
-
-func (d *DefaultsModuleBase) setProtectedProperties(protectedProperties []string) {
- d.defaultsProperties.Protected_properties = protectedProperties
-}
-
func (d *DefaultsModuleBase) properties() []interface{} {
return d.defaultableProperties
}
@@ -232,10 +190,6 @@
&ApexProperties{},
&distProperties{})
- // Additional properties of defaults modules that can themselves have
- // defaults applied.
- module.AddProperties(module.additionalDefaultableProperties()...)
-
// Bazel module must be initialized _before_ Defaults to be included in cc_defaults module.
InitBazelModule(module)
initAndroidModuleBase(module)
@@ -263,58 +217,6 @@
// The applicable licenses property for defaults is 'licenses'.
setPrimaryLicensesProperty(module, "licenses", &commonProperties.Licenses)
-
- AddLoadHook(module, func(ctx LoadHookContext) {
-
- protectedProperties := module.protectedProperties()
- if len(protectedProperties) == 0 {
- return
- }
-
- propertiesAvailable := map[string]struct{}{}
- propertiesSet := map[string]struct{}{}
-
- // A defaults tracker which will keep track of which properties have been set on this module.
- collector := func(defaults DefaultsModule, property string, dstValue interface{}, srcValue interface{}) bool {
- value := reflect.ValueOf(dstValue)
- propertiesAvailable[property] = struct{}{}
- if !value.IsZero() {
- propertiesSet[property] = struct{}{}
- }
- // Skip all the properties so that there are no changes to the defaults.
- return false
- }
-
- // Try and apply this module's defaults to itself, so that the properties can be collected but
- // skip all the properties so it doesn't actually do anything.
- module.applySingleDefaultsWithTracker(ctx, module, collector)
-
- if InList("*", protectedProperties) {
- if len(protectedProperties) != 1 {
- ctx.PropertyErrorf("protected_properties", `if specified then "*" must be the only property listed`)
- return
- }
-
- // Do not automatically protect the protected_properties property.
- delete(propertiesSet, "protected_properties")
-
- // Or the visibility property.
- delete(propertiesSet, "visibility")
-
- // Replace the "*" with the names of all the properties that have been set.
- protectedProperties = SortedStringKeys(propertiesSet)
- module.setProtectedProperties(protectedProperties)
- } else {
- for _, property := range protectedProperties {
- if _, ok := propertiesAvailable[property]; !ok {
- ctx.PropertyErrorf(property, "property is not supported by this module type %q",
- ctx.ModuleType())
- } else if _, ok := propertiesSet[property]; !ok {
- ctx.PropertyErrorf(property, "is not set; protected properties must be explicitly set")
- }
- }
- }
- })
}
var _ Defaults = (*DefaultsModuleBase)(nil)
@@ -366,204 +268,35 @@
b.setNamespacedVariableProps(dst)
}
-// defaultValueInfo contains information about each default value that applies to a protected
-// property.
-type defaultValueInfo struct {
- // The DefaultsModule providing the value, which may be defined on that module or applied as a
- // default from other modules.
- module Module
-
- // The default value, as returned by getComparableValue
- defaultValue reflect.Value
-}
-
-// protectedPropertyInfo contains information about each property that has to be protected when
-// applying defaults.
-type protectedPropertyInfo struct {
- // True if the property was set on the module to which defaults are applied, this is an error.
- propertySet bool
-
- // The original value of the property on the module, as returned by getComparableValue.
- originalValue reflect.Value
-
- // A list of defaults for the property that are being applied.
- defaultValues []defaultValueInfo
-}
-
-// getComparableValue takes a reflect.Value that may be a pointer to another value and returns a
-// reflect.Value to the underlying data or the original if was not a pointer or was nil. The
-// returned values can then be compared for equality.
-func getComparableValue(value reflect.Value) reflect.Value {
- if value.IsZero() {
- return value
- }
- for value.Kind() == reflect.Ptr {
- value = value.Elem()
- }
- return value
-}
-
func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContext,
- defaultsList []DefaultsModule) {
-
- // Collate information on all the properties protected by each of the default modules applied
- // to this module.
- allProtectedProperties := map[string]*protectedPropertyInfo{}
- for _, defaults := range defaultsList {
- for _, property := range defaults.protectedProperties() {
- info := allProtectedProperties[property]
- if info == nil {
- info = &protectedPropertyInfo{}
- allProtectedProperties[property] = info
- }
- }
- }
-
- // If there are any protected properties then collate information about attempts to change them.
- var protectedPropertyInfoCollector defaultsTrackerFunc
- if len(allProtectedProperties) > 0 {
- protectedPropertyInfoCollector = func(defaults DefaultsModule, property string,
- dstValue interface{}, srcValue interface{}) bool {
-
- // If the property is not protected then return immediately.
- info := allProtectedProperties[property]
- if info == nil {
- return true
- }
-
- currentValue := reflect.ValueOf(dstValue)
- if info.defaultValues == nil {
- info.propertySet = !currentValue.IsZero()
- info.originalValue = getComparableValue(currentValue)
- }
-
- defaultValue := reflect.ValueOf(srcValue)
- if !defaultValue.IsZero() {
- info.defaultValues = append(info.defaultValues,
- defaultValueInfo{defaults, getComparableValue(defaultValue)})
- }
-
- return true
- }
- }
+ defaultsList []Defaults) {
for _, defaults := range defaultsList {
if ctx.Config().BuildMode == Bp2build {
applyNamespacedVariableDefaults(defaults, ctx)
}
-
- defaultable.applySingleDefaultsWithTracker(ctx, defaults, protectedPropertyInfoCollector)
- }
-
- // Check the status of any protected properties.
- for property, info := range allProtectedProperties {
- if len(info.defaultValues) == 0 {
- // No defaults were applied to the protected properties. Possibly because this module type
- // does not support any of them.
- continue
- }
-
- // Check to make sure that there are no conflicts between the defaults.
- conflictingDefaults := false
- previousDefaultValue := reflect.ValueOf(false)
- for _, defaultInfo := range info.defaultValues {
- defaultValue := defaultInfo.defaultValue
- if previousDefaultValue.IsZero() {
- previousDefaultValue = defaultValue
- } else if !reflect.DeepEqual(previousDefaultValue.Interface(), defaultValue.Interface()) {
- conflictingDefaults = true
- break
- }
- }
-
- if conflictingDefaults {
- var buf bytes.Buffer
- for _, defaultInfo := range info.defaultValues {
- buf.WriteString(fmt.Sprintf("\n defaults module %q provides value %#v",
- ctx.OtherModuleName(defaultInfo.module), defaultInfo.defaultValue))
- }
- result := buf.String()
- ctx.ModuleErrorf("has conflicting default values for protected property %q:%s", property, result)
- continue
- }
-
- // Now check to see whether there the current module tried to override/append to the defaults.
- if info.propertySet {
- originalValue := info.originalValue
- // Just compare against the first defaults.
- defaultValue := info.defaultValues[0].defaultValue
- defaults := info.defaultValues[0].module
-
- if originalValue.Kind() == reflect.Slice {
- ctx.ModuleErrorf("attempts to append %q to protected property %q's value of %q defined in module %q",
- originalValue,
- property,
- defaultValue,
- ctx.OtherModuleName(defaults))
+ for _, prop := range defaultable.defaultableProperties {
+ if prop == defaultable.defaultableVariableProperties {
+ defaultable.applyDefaultVariableProperties(ctx, defaults, prop)
} else {
- same := reflect.DeepEqual(originalValue.Interface(), defaultValue.Interface())
- message := ""
- if same {
- message = fmt.Sprintf(" with a matching value (%#v) so this property can simply be removed.", originalValue)
- } else {
- message = fmt.Sprintf(" with a different value (override %#v with %#v) so removing the property may necessitate other changes.", defaultValue, originalValue)
- }
- ctx.ModuleErrorf("attempts to override protected property %q defined in module %q%s",
- property,
- ctx.OtherModuleName(defaults), message)
+ defaultable.applyDefaultProperties(ctx, defaults, prop)
}
}
}
}
-func (defaultable *DefaultableModuleBase) applySingleDefaultsWithTracker(ctx EarlyModuleContext, defaults DefaultsModule, tracker defaultsTrackerFunc) {
- for _, prop := range defaultable.defaultableProperties {
- var err error
- if prop == defaultable.defaultableVariableProperties {
- err = defaultable.applyDefaultVariableProperties(defaults, prop, tracker)
- } else {
- err = defaultable.applyDefaultProperties(defaults, prop, tracker)
- }
- if err != nil {
- if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
- ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
- } else {
- panic(err)
- }
- }
- }
-}
-
-// defaultsTrackerFunc is the type of a function that can be used to track how defaults are applied.
-type defaultsTrackerFunc func(defaults DefaultsModule, property string,
- dstValue interface{}, srcValue interface{}) bool
-
-// filterForTracker wraps a defaultsTrackerFunc in a proptools.ExtendPropertyFilterFunc
-func filterForTracker(defaults DefaultsModule, tracker defaultsTrackerFunc) proptools.ExtendPropertyFilterFunc {
- if tracker == nil {
- return nil
- }
- return func(property string,
- dstField, srcField reflect.StructField,
- dstValue, srcValue interface{}) (bool, error) {
-
- apply := tracker(defaults, property, dstValue, srcValue)
- return apply, nil
- }
-}
-
// Product variable properties need special handling, the type of the filtered product variable
// property struct may not be identical between the defaults module and the defaultable module.
// Use PrependMatchingProperties to apply whichever properties match.
-func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(defaults DefaultsModule,
- defaultableProp interface{}, tracker defaultsTrackerFunc) error {
+func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx TopDownMutatorContext,
+ defaults Defaults, defaultableProp interface{}) {
if defaultableProp == nil {
- return nil
+ return
}
defaultsProp := defaults.productVariableProperties()
if defaultsProp == nil {
- return nil
+ return
}
dst := []interface{}{
@@ -573,26 +306,31 @@
proptools.CloneEmptyProperties(reflect.ValueOf(defaultsProp)).Interface(),
}
- filter := filterForTracker(defaults, tracker)
-
- return proptools.PrependMatchingProperties(dst, defaultsProp, filter)
+ err := proptools.PrependMatchingProperties(dst, defaultsProp, nil)
+ if err != nil {
+ if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
+ ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+ } else {
+ panic(err)
+ }
+ }
}
-func (defaultable *DefaultableModuleBase) applyDefaultProperties(defaults DefaultsModule,
- defaultableProp interface{}, checker defaultsTrackerFunc) error {
-
- filter := filterForTracker(defaults, checker)
+func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext,
+ defaults Defaults, defaultableProp interface{}) {
for _, def := range defaults.properties() {
if proptools.TypeEqual(defaultableProp, def) {
- err := proptools.PrependProperties(defaultableProp, def, filter)
+ err := proptools.PrependProperties(defaultableProp, def, nil)
if err != nil {
- return err
+ if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
+ ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+ } else {
+ panic(err)
+ }
}
}
}
-
- return nil
}
func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) {
@@ -609,12 +347,12 @@
func defaultsMutator(ctx TopDownMutatorContext) {
if defaultable, ok := ctx.Module().(Defaultable); ok {
if len(defaultable.defaults().Defaults) > 0 {
- var defaultsList []DefaultsModule
+ var defaultsList []Defaults
seen := make(map[Defaults]bool)
ctx.WalkDeps(func(module, parent Module) bool {
if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
- if defaults, ok := module.(DefaultsModule); ok {
+ if defaults, ok := module.(Defaults); ok {
if !seen[defaults] {
seen[defaults] = true
defaultsList = append(defaultsList, defaults)
@@ -630,6 +368,6 @@
defaultable.applyDefaults(ctx, defaultsList)
}
- defaultable.callHookIfAvailable(ctx)
+ defaultable.CallHookIfAvailable(ctx)
}
}
diff --git a/android/defaults_test.go b/android/defaults_test.go
index d80f40c..a7542ab 100644
--- a/android/defaults_test.go
+++ b/android/defaults_test.go
@@ -19,14 +19,7 @@
)
type defaultsTestProperties struct {
- Foo []string
- Bar []string
- Nested struct {
- Fizz *bool
- }
- Other struct {
- Buzz *string
- }
+ Foo []string
}
type defaultsTestModule struct {
@@ -137,167 +130,3 @@
// TODO: missing transitive defaults is currently not handled
_ = missingTransitiveDefaults
}
-
-func TestProtectedProperties_ProtectedPropertyNotSet(t *testing.T) {
- bp := `
- defaults {
- name: "transitive",
- protected_properties: ["foo"],
- }
- `
-
- GroupFixturePreparers(
- prepareForDefaultsTest,
- FixtureWithRootAndroidBp(bp),
- ).ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(
- "module \"transitive\": foo: is not set; protected properties must be explicitly set")).
- RunTest(t)
-}
-
-func TestProtectedProperties_ProtectedPropertyNotLeaf(t *testing.T) {
- bp := `
- defaults {
- name: "transitive",
- protected_properties: ["nested"],
- nested: {
- fizz: true,
- },
- }
- `
-
- GroupFixturePreparers(
- prepareForDefaultsTest,
- FixtureWithRootAndroidBp(bp),
- ).ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(
- `\Qmodule "transitive": nested: property is not supported by this module type "defaults"\E`)).
- RunTest(t)
-}
-
-// TestProtectedProperties_ApplyDefaults makes sure that the protected_properties property has
-// defaults applied.
-func TestProtectedProperties_HasDefaultsApplied(t *testing.T) {
-
- bp := `
- defaults {
- name: "transitive",
- protected_properties: ["foo"],
- foo: ["transitive"],
- }
-
- defaults {
- name: "defaults",
- defaults: ["transitive"],
- protected_properties: ["bar"],
- bar: ["defaults"],
- }
- `
-
- result := GroupFixturePreparers(
- prepareForDefaultsTest,
- FixtureWithRootAndroidBp(bp),
- ).RunTest(t)
-
- defaults := result.Module("defaults", "").(DefaultsModule)
- AssertDeepEquals(t, "defaults protected properties", []string{"foo", "bar"}, defaults.protectedProperties())
-}
-
-// TestProtectedProperties_ProtectAllProperties makes sure that protected_properties: ["*"] protects
-// all properties.
-func TestProtectedProperties_ProtectAllProperties(t *testing.T) {
-
- bp := `
- defaults {
- name: "transitive",
- protected_properties: ["other.buzz"],
- other: {
- buzz: "transitive",
- },
- }
-
- defaults {
- name: "defaults",
- defaults: ["transitive"],
- visibility: ["//visibility:private"],
- protected_properties: ["*"],
- foo: ["other"],
- bar: ["defaults"],
- nested: {
- fizz: true,
- }
- }
- `
-
- result := GroupFixturePreparers(
- prepareForDefaultsTest,
- FixtureWithRootAndroidBp(bp),
- ).RunTest(t)
-
- defaults := result.Module("defaults", "").(DefaultsModule)
- AssertDeepEquals(t, "defaults protected properties", []string{"other.buzz", "bar", "foo", "nested.fizz"},
- defaults.protectedProperties())
-}
-
-func TestProtectedProperties_DetectedOverride(t *testing.T) {
- bp := `
- defaults {
- name: "defaults",
- protected_properties: ["foo", "nested.fizz"],
- foo: ["defaults"],
- nested: {
- fizz: true,
- },
- }
-
- test {
- name: "foo",
- defaults: ["defaults"],
- foo: ["module"],
- nested: {
- fizz: false,
- },
- }
- `
-
- GroupFixturePreparers(
- prepareForDefaultsTest,
- FixtureWithRootAndroidBp(bp),
- ).ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(
- []string{
- `\Qmodule "foo": attempts to append ["module"] to protected property "foo"'s value of ["defaults"] defined in module "defaults"\E`,
- `\Qmodule "foo": attempts to override protected property "nested.fizz" defined in module "defaults" with a different value (override true with false) so removing the property may necessitate other changes.\E`,
- })).RunTest(t)
-}
-
-func TestProtectedProperties_DefaultsConflict(t *testing.T) {
- bp := `
- defaults {
- name: "defaults1",
- protected_properties: ["other.buzz"],
- other: {
- buzz: "value",
- },
- }
-
- defaults {
- name: "defaults2",
- protected_properties: ["other.buzz"],
- other: {
- buzz: "another",
- },
- }
-
- test {
- name: "foo",
- defaults: ["defaults1", "defaults2"],
- }
- `
-
- GroupFixturePreparers(
- prepareForDefaultsTest,
- FixtureWithRootAndroidBp(bp),
- ).ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(
- `\Qmodule "foo": has conflicting default values for protected property "other.buzz":
- defaults module "defaults1" provides value "value"
- defaults module "defaults2" provides value "another"\E`,
- )).RunTest(t)
-}
diff --git a/android/defs.go b/android/defs.go
index 6e5bb05..18eed2d 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -58,6 +58,14 @@
},
"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 d21d146..278d46d 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -26,13 +26,18 @@
)
func init() {
- RegisterModuleType("filegroup", FileGroupFactory)
+ RegisterFilegroupBuildComponents(InitRegistrationContext)
}
var PrepareForTestWithFilegroup = FixtureRegisterWithContext(func(ctx RegistrationContext) {
- ctx.RegisterModuleType("filegroup", FileGroupFactory)
+ RegisterFilegroupBuildComponents(ctx)
})
+func RegisterFilegroupBuildComponents(ctx RegistrationContext) {
+ ctx.RegisterModuleType("filegroup", FileGroupFactory)
+ ctx.RegisterModuleType("filegroup_defaults", FileGroupDefaultsFactory)
+}
+
var convertedProtoLibrarySuffix = "_bp2build_converted"
// IsFilegroup checks that a module is a filegroup type
@@ -78,6 +83,12 @@
Strip_import_prefix *string
}
+// api srcs can be contained in filegroups.
+// this should be generated in api_bp2build workspace as well.
+func (fg *fileGroup) ConvertWithApiBp2build(ctx TopDownMutatorContext) {
+ fg.ConvertWithBp2build(ctx)
+}
+
// ConvertWithBp2build performs bp2build conversion of filegroup
func (fg *fileGroup) ConvertWithBp2build(ctx TopDownMutatorContext) {
srcs := bazel.MakeLabelListAttribute(
@@ -172,6 +183,7 @@
type fileGroup struct {
ModuleBase
BazelModuleBase
+ DefaultableModuleBase
FileGroupAsLibrary
properties fileGroupProperties
srcs Paths
@@ -189,6 +201,7 @@
module.AddProperties(&module.properties)
InitAndroidModule(module)
InitBazelModule(module)
+ InitDefaultableModule(module)
return module
}
@@ -232,7 +245,7 @@
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 +265,7 @@
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
@@ -320,3 +333,17 @@
}
return nil, false
}
+
+// Defaults
+type FileGroupDefaults struct {
+ ModuleBase
+ DefaultsModuleBase
+}
+
+func FileGroupDefaultsFactory() Module {
+ module := &FileGroupDefaults{}
+ module.AddProperties(&fileGroupProperties{})
+ InitDefaultsModule(module)
+
+ return module
+}
diff --git a/android/filegroup_test.go b/android/filegroup_test.go
index 8292d5e..893da57 100644
--- a/android/filegroup_test.go
+++ b/android/filegroup_test.go
@@ -58,3 +58,24 @@
AssertStringEquals(t, "src full path", expectedOutputfile, fg.srcs[0].String())
}
}
+
+func TestFilegroupDefaults(t *testing.T) {
+ bp := FixtureAddTextFile("p/Android.bp", `
+ filegroup_defaults {
+ name: "defaults",
+ visibility: ["//x"],
+ }
+ filegroup {
+ name: "foo",
+ defaults: ["defaults"],
+ visibility: ["//y"],
+ }
+ `)
+ result := GroupFixturePreparers(
+ PrepareForTestWithFilegroup,
+ PrepareForTestWithDefaults,
+ PrepareForTestWithVisibility,
+ bp).RunTest(t)
+ rules := effectiveVisibilityRules(result.Config, qualifiedModuleName{pkg: "p", name: "foo"})
+ AssertDeepEquals(t, "visibility", []string{"//x", "//y"}, rules.Strings())
+}
diff --git a/android/module.go b/android/module.go
index 681f724..76fe8dc 100644
--- a/android/module.go
+++ b/android/module.go
@@ -37,26 +37,64 @@
DeviceStaticLibrary = "static_library"
)
+// BuildParameters describes the set of potential parameters to build a Ninja rule.
+// In general, these correspond to a Ninja concept.
type BuildParams struct {
- Rule blueprint.Rule
- Deps blueprint.Deps
- Depfile WritablePath
- Description string
- Output WritablePath
- Outputs WritablePaths
- SymlinkOutput WritablePath
- SymlinkOutputs WritablePaths
- ImplicitOutput WritablePath
+ // A Ninja Rule that will be written to the Ninja file. This allows factoring out common code
+ // among multiple modules to reduce repetition in the Ninja file of action requirements. A rule
+ // can contain variables that should be provided in Args.
+ Rule blueprint.Rule
+ // Deps represents the depfile format. When using RuleBuilder, this defaults to GCC when depfiles
+ // are used.
+ Deps blueprint.Deps
+ // Depfile is a writeable path that allows correct incremental builds when the inputs have not
+ // been fully specified by the Ninja rule. Ninja supports a subset of the Makefile depfile syntax.
+ Depfile WritablePath
+ // A description of the build action.
+ Description string
+ // Output is an output file of the action. When using this field, references to $out in the Ninja
+ // command will refer to this file.
+ Output WritablePath
+ // Outputs is a slice of output file of the action. When using this field, references to $out in
+ // the Ninja command will refer to these files.
+ Outputs WritablePaths
+ // SymlinkOutput is an output file specifically that is a symlink.
+ SymlinkOutput WritablePath
+ // SymlinkOutputs is a slice of output files specifically that is a symlink.
+ SymlinkOutputs WritablePaths
+ // ImplicitOutput is an output file generated by the action. Note: references to `$out` in the
+ // Ninja command will NOT include references to this file.
+ ImplicitOutput WritablePath
+ // ImplicitOutputs is a slice of output files generated by the action. Note: references to `$out`
+ // in the Ninja command will NOT include references to these files.
ImplicitOutputs WritablePaths
- Input Path
- Inputs Paths
- Implicit Path
- Implicits Paths
- OrderOnly Paths
- Validation Path
- Validations Paths
- Default bool
- Args map[string]string
+ // Input is an input file to the Ninja action. When using this field, references to $in in the
+ // Ninja command will refer to this file.
+ Input Path
+ // Inputs is a slice of input files to the Ninja action. When using this field, references to $in
+ // in the Ninja command will refer to these files.
+ Inputs Paths
+ // Implicit is an input file to the Ninja action. Note: references to `$in` in the Ninja command
+ // will NOT include references to this file.
+ Implicit Path
+ // Implicits is a slice of input files to the Ninja action. Note: references to `$in` in the Ninja
+ // command will NOT include references to these files.
+ Implicits Paths
+ // OrderOnly are Ninja order-only inputs to the action. When these are out of date, the output is
+ // not rebuilt until they are built, but changes in order-only dependencies alone do not cause the
+ // output to be rebuilt.
+ OrderOnly Paths
+ // Validation is an output path for a validation action. Validation outputs imply lower
+ // non-blocking priority to building non-validation outputs.
+ Validation Path
+ // Validations is a slice of output path for a validation action. Validation outputs imply lower
+ // non-blocking priority to building non-validation outputs.
+ Validations Paths
+ // Whether to skip outputting a default target statement which will be built by Ninja when no
+ // targets are specified on Ninja's command line.
+ Default bool
+ // Args is a key value mapping for replacements of variables within the Rule
+ Args map[string]string
}
type ModuleBuildParams BuildParams
@@ -502,6 +540,7 @@
InstallInRoot() bool
InstallInVendor() bool
InstallForceOS() (*OsType, *ArchType)
+ PartitionTag(DeviceConfig) string
HideFromMake()
IsHideFromMake() bool
IsSkipInstall() bool
@@ -1333,7 +1372,7 @@
// Check product variables for `enabled: true` flag override.
// Returns a list of the constraint_value targets who enable this override.
func productVariableConfigEnableLabels(ctx *topDownMutatorContext) []bazel.Label {
- productVariableProps := ProductVariableProperties(ctx)
+ productVariableProps := ProductVariableProperties(ctx, ctx.Module())
productConfigEnablingTargets := []bazel.Label{}
const propName = "Enabled"
if productConfigProps, exists := productVariableProps[propName]; exists {
@@ -3674,7 +3713,7 @@
// 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 +3724,7 @@
dir = parentDir(dir)
}
}
- dirs = SortedStringKeys(dirMap)
+ dirs = SortedKeys(dirMap)
var topDirs []string
for _, dir := range dirs {
p := parentDir(dir)
@@ -3695,7 +3734,7 @@
topDirs = append(topDirs, dir)
}
}
- return SortedStringKeys(dirMap), topDirs
+ return SortedKeys(dirMap), topDirs
}
func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) {
@@ -3781,7 +3820,7 @@
}
// 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 4e55609..676f8a5 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -268,6 +268,11 @@
// platforms, as dictated by a given bool attribute: the target will not be buildable in
// any platform for which this bool attribute is false.
CreateBazelTargetModuleWithRestrictions(bazel.BazelTargetModuleProperties, CommonAttributes, interface{}, bazel.BoolAttribute)
+
+ // CreateBazelTargetAliasInDir creates an alias definition in `dir` directory.
+ // This function can be used to create alias definitions in a directory that is different
+ // from the directory of the visited Soong module.
+ CreateBazelTargetAliasInDir(dir string, name string, actual bazel.Label)
}
type topDownMutatorContext struct {
@@ -705,28 +710,61 @@
t.createBazelTargetModule(bazelProps, commonAttrs, attrs, enabledProperty)
}
+var (
+ bazelAliasModuleProperties = bazel.BazelTargetModuleProperties{
+ Rule_class: "alias",
+ }
+)
+
+type bazelAliasAttributes struct {
+ Actual *bazel.LabelAttribute
+}
+
+func (t *topDownMutatorContext) CreateBazelTargetAliasInDir(
+ dir string,
+ name string,
+ actual bazel.Label) {
+ mod := t.Module()
+ attrs := &bazelAliasAttributes{
+ Actual: bazel.MakeLabelAttribute(actual.Label),
+ }
+ info := bp2buildInfo{
+ Dir: dir,
+ BazelProps: bazelAliasModuleProperties,
+ CommonAttrs: CommonAttributes{Name: name},
+ ConstraintAttrs: constraintAttributes{},
+ Attrs: attrs,
+ }
+ mod.base().addBp2buildInfo(info)
+}
+
// ApexAvailableTags converts the apex_available property value of an ApexModule
// 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 21eebd2..dbdfa33 100644
--- a/android/mutator_test.go
+++ b/android/mutator_test.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "reflect"
"strings"
"testing"
@@ -267,3 +268,22 @@
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 ad9880a..2139c3c 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -165,6 +165,7 @@
javaDeviceForHostProjectsAllowedList := []string{
"development/build",
"external/guava",
+ "external/kotlinx.coroutines",
"external/robolectric-shadows",
"external/robolectric",
"frameworks/layoutlib",
@@ -542,7 +543,7 @@
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 ecd84a2..4a9b591 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -240,7 +240,7 @@
// 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 0fc39df..eaa6a8d 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -16,7 +16,6 @@
import (
"fmt"
- "io/ioutil"
"os"
"path/filepath"
"reflect"
@@ -1710,10 +1709,10 @@
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 @@
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 @@
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 @@
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 @@
// 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 0adbb55..814a9e3 100644
--- a/android/phony.go
+++ b/android/phony.go
@@ -48,7 +48,7 @@
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 8953eae..cace88a 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -84,6 +84,40 @@
}
}
+// JavaLibraryName returns the soong module containing the Java APIs of that API surface.
+func (k SdkKind) JavaLibraryName(c Config) string {
+ name := k.defaultJavaLibraryName()
+ return JavaLibraryNameFromText(c, name)
+}
+
+// JavaLibraryNameFromText returns the name of .txt equivalent of a java_library, but does
+// not check if either module exists.
+// TODO: Return .txt (single-tree or multi-tree equivalents) based on config
+func JavaLibraryNameFromText(c Config, name string) string {
+ // This returns the default for now.
+ // TODO: Implement this
+ return name
+}
+
+func (k SdkKind) defaultJavaLibraryName() string {
+ switch k {
+ case SdkPublic:
+ return "android_stubs_current"
+ case SdkSystem:
+ return "android_system_stubs_current"
+ case SdkTest:
+ return "android_test_stubs_current"
+ case SdkCore:
+ return "core.current.stubs"
+ case SdkModule:
+ return "android_module_lib_stubs_current"
+ case SdkSystemServer:
+ return "android_system_server_stubs_current"
+ default:
+ panic(fmt.Errorf("APIs of API surface %v cannot be provided by a single Soong module\n", k))
+ }
+}
+
// SdkSpec represents the kind and the version of an SDK for a module to build against
type SdkSpec struct {
Kind SdkKind
@@ -211,7 +245,29 @@
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/soong_config_modules.go b/android/soong_config_modules.go
index 9f5440d..5fa6012 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -396,7 +396,7 @@
}
if ctx.Config().BuildMode == Bp2build {
- ctx.Config().Bp2buildSoongConfigDefinitions.AddVars(*mtDef)
+ ctx.Config().Bp2buildSoongConfigDefinitions.AddVars(mtDef)
}
globalModuleTypes := ctx.moduleFactories()
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index ed4888d..23c8afa 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -240,12 +240,7 @@
// string vars, bool vars and value vars created by every
// soong_config_module_type in this build.
type Bp2BuildSoongConfigDefinitions struct {
- // varCache contains a cache of string variables namespace + property
- // The same variable may be used in multiple module types (for example, if need support
- // for cc_default and java_default), only need to process once
- varCache map[string]bool
-
- StringVars map[string][]string
+ StringVars map[string]map[string]bool
BoolVars map[string]bool
ValueVars map[string]bool
}
@@ -255,7 +250,7 @@
// SoongConfigVariablesForBp2build extracts information from a
// SoongConfigDefinition that bp2build needs to generate constraint settings and
// values for, in order to migrate soong_config_module_type usages to Bazel.
-func (defs *Bp2BuildSoongConfigDefinitions) AddVars(mtDef SoongConfigDefinition) {
+func (defs *Bp2BuildSoongConfigDefinitions) AddVars(mtDef *SoongConfigDefinition) {
// In bp2build mode, this method is called concurrently in goroutines from
// loadhooks while parsing soong_config_module_type, so add a mutex to
// prevent concurrent map writes. See b/207572723
@@ -263,7 +258,7 @@
defer bp2buildSoongConfigVarsLock.Unlock()
if defs.StringVars == nil {
- defs.StringVars = make(map[string][]string)
+ defs.StringVars = make(map[string]map[string]bool)
}
if defs.BoolVars == nil {
defs.BoolVars = make(map[string]bool)
@@ -271,24 +266,29 @@
if defs.ValueVars == nil {
defs.ValueVars = make(map[string]bool)
}
- if defs.varCache == nil {
- defs.varCache = make(map[string]bool)
- }
+ // varCache contains a cache of string variables namespace + property
+ // The same variable may be used in multiple module types (for example, if need support
+ // for cc_default and java_default), only need to process once
+ varCache := map[string]bool{}
+
for _, moduleType := range mtDef.ModuleTypes {
for _, v := range moduleType.Variables {
key := strings.Join([]string{moduleType.ConfigNamespace, v.variableProperty()}, "__")
// The same variable may be used in multiple module types (for example, if need support
// for cc_default and java_default), only need to process once
- if _, keyInCache := defs.varCache[key]; keyInCache {
+ if _, keyInCache := varCache[key]; keyInCache {
continue
} else {
- defs.varCache[key] = true
+ varCache[key] = true
}
if strVar, ok := v.(*stringVariable); ok {
+ if _, ok := defs.StringVars[key]; !ok {
+ defs.StringVars[key] = make(map[string]bool, len(strVar.values))
+ }
for _, value := range strVar.values {
- defs.StringVars[key] = append(defs.StringVars[key], value)
+ defs.StringVars[key][value] = true
}
} else if _, ok := v.(*boolVariable); ok {
defs.BoolVars[key] = true
@@ -329,8 +329,13 @@
ret += starlark_fmt.PrintBoolDict(defs.ValueVars, 0)
ret += "\n\n"
+ stringVars := make(map[string][]string, len(defs.StringVars))
+ for k, v := range defs.StringVars {
+ stringVars[k] = sortedStringKeys(v)
+ }
+
ret += "soong_config_string_variables = "
- ret += starlark_fmt.PrintStringListDict(defs.StringVars, 0)
+ ret += starlark_fmt.PrintStringListDict(stringVars, 0)
return ret
}
diff --git a/android/soongconfig/modules_test.go b/android/soongconfig/modules_test.go
index d5d87ef..a5fa349 100644
--- a/android/soongconfig/modules_test.go
+++ b/android/soongconfig/modules_test.go
@@ -414,6 +414,110 @@
}
}
+func Test_Bp2BuildSoongConfigDefinitionsAddVars(t *testing.T) {
+ testCases := []struct {
+ desc string
+ defs []*SoongConfigDefinition
+ expected Bp2BuildSoongConfigDefinitions
+ }{
+ {
+ desc: "non-overlapping",
+ defs: []*SoongConfigDefinition{
+ &SoongConfigDefinition{
+ ModuleTypes: map[string]*ModuleType{
+ "a": &ModuleType{
+ ConfigNamespace: "foo",
+ Variables: []soongConfigVariable{
+ &stringVariable{
+ baseVariable: baseVariable{"string_var"},
+ values: []string{"a", "b", "c"},
+ },
+ },
+ },
+ },
+ },
+ &SoongConfigDefinition{
+ ModuleTypes: map[string]*ModuleType{
+ "b": &ModuleType{
+ ConfigNamespace: "foo",
+ Variables: []soongConfigVariable{
+ &stringVariable{
+ baseVariable: baseVariable{"string_var"},
+ values: []string{"a", "b", "c"},
+ },
+ &boolVariable{baseVariable: baseVariable{"bool_var"}},
+ &valueVariable{baseVariable: baseVariable{"variable_var"}},
+ },
+ },
+ },
+ },
+ },
+ expected: Bp2BuildSoongConfigDefinitions{
+ StringVars: map[string]map[string]bool{
+ "foo__string_var": map[string]bool{"a": true, "b": true, "c": true},
+ },
+ BoolVars: map[string]bool{"foo__bool_var": true},
+ ValueVars: map[string]bool{"foo__variable_var": true},
+ },
+ },
+ {
+ desc: "overlapping",
+ defs: []*SoongConfigDefinition{
+ &SoongConfigDefinition{
+ ModuleTypes: map[string]*ModuleType{
+ "a": &ModuleType{
+ ConfigNamespace: "foo",
+ Variables: []soongConfigVariable{
+ &stringVariable{
+ baseVariable: baseVariable{"string_var"},
+ values: []string{"a", "b", "c"},
+ },
+ },
+ },
+ },
+ },
+ &SoongConfigDefinition{
+ ModuleTypes: map[string]*ModuleType{
+ "b": &ModuleType{
+ ConfigNamespace: "foo",
+ Variables: []soongConfigVariable{
+ &stringVariable{
+ baseVariable: baseVariable{"string_var"},
+ values: []string{"b", "c", "d"},
+ },
+ &boolVariable{baseVariable: baseVariable{"bool_var"}},
+ &valueVariable{baseVariable: baseVariable{"variable_var"}},
+ },
+ },
+ },
+ },
+ },
+ expected: Bp2BuildSoongConfigDefinitions{
+ StringVars: map[string]map[string]bool{
+ "foo__string_var": map[string]bool{"a": true, "b": true, "c": true, "d": true},
+ },
+ BoolVars: map[string]bool{"foo__bool_var": true},
+ ValueVars: map[string]bool{"foo__variable_var": true},
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ actual := &Bp2BuildSoongConfigDefinitions{}
+ for _, d := range tc.defs {
+ func(def *SoongConfigDefinition) {
+ actual.AddVars(def)
+ }(d)
+ }
+ if !reflect.DeepEqual(*actual, tc.expected) {
+ t.Errorf("Expected %#v, got %#v", tc.expected, *actual)
+ }
+ })
+ }
+
+}
+
func Test_Bp2BuildSoongConfigDefinitions(t *testing.T) {
testCases := []struct {
desc string
@@ -456,11 +560,11 @@
soong_config_string_variables = {}`}, {
desc: "only string vars",
defs: Bp2BuildSoongConfigDefinitions{
- StringVars: map[string][]string{
- "string_var": []string{
- "choice1",
- "choice2",
- "choice3",
+ StringVars: map[string]map[string]bool{
+ "string_var": map[string]bool{
+ "choice1": true,
+ "choice2": true,
+ "choice3": true,
},
},
},
@@ -484,15 +588,15 @@
"value_var_one": true,
"value_var_two": true,
},
- StringVars: map[string][]string{
- "string_var_one": []string{
- "choice1",
- "choice2",
- "choice3",
+ StringVars: map[string]map[string]bool{
+ "string_var_one": map[string]bool{
+ "choice1": true,
+ "choice2": true,
+ "choice3": true,
},
- "string_var_two": []string{
- "foo",
- "bar",
+ "string_var_two": map[string]bool{
+ "foo": true,
+ "bar": true,
},
},
},
@@ -512,8 +616,8 @@
"choice3",
],
"string_var_two": [
- "foo",
"bar",
+ "foo",
],
}`},
}
diff --git a/android/test_suites.go b/android/test_suites.go
index 55e1da7..b570b23 100644
--- a/android/test_suites.go
+++ b/android/test_suites.go
@@ -57,7 +57,7 @@
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 947af69..38e0a4d 100644
--- a/android/util.go
+++ b/android/util.go
@@ -29,6 +29,15 @@
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 @@
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 ""
- }
-
- 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()
+// 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)
}
-// 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 {
+type Ordered interface {
+ ~string |
+ ~float32 | ~float64 |
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+}
+
+// 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 9b9253b..5584b38 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -641,42 +641,34 @@
}
}
-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 %v, got %v", 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 e714fc4..8c5c0bc 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -64,6 +64,12 @@
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"`
@@ -436,6 +442,7 @@
BuildBrokenDepfile *bool `json:",omitempty"`
BuildBrokenEnforceSyspropOwner bool `json:",omitempty"`
BuildBrokenTrebleSyspropNeverallow bool `json:",omitempty"`
+ BuildBrokenUsesSoongPython2Modules bool `json:",omitempty"`
BuildBrokenVendorPropertyNamespace bool `json:",omitempty"`
BuildBrokenInputDirModules []string `json:",omitempty"`
@@ -657,9 +664,8 @@
type ProductConfigProperties map[string]map[ProductConfigProperty]interface{}
// ProductVariableProperties returns a ProductConfigProperties containing only the properties which
-// have been set for the module in the given context.
-func ProductVariableProperties(ctx BazelConversionPathContext) ProductConfigProperties {
- module := ctx.Module()
+// have been set for the given module.
+func ProductVariableProperties(ctx ArchVariantContext, module Module) ProductConfigProperties {
moduleBase := module.base()
productConfigProperties := ProductConfigProperties{}
diff --git a/android_sdk/sdk_repo_host.go b/android_sdk/sdk_repo_host.go
index f646742..61058df 100644
--- a/android_sdk/sdk_repo_host.go
+++ b/android_sdk/sdk_repo_host.go
@@ -166,10 +166,9 @@
}
} 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/Android.bp b/apex/Android.bp
index 018d030..7ffca0e 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -29,6 +29,7 @@
"bp2build.go",
"deapexer.go",
"key.go",
+ "metadata.go",
"prebuilt.go",
"testing.go",
"vndk.go",
@@ -37,6 +38,7 @@
"apex_test.go",
"bootclasspath_fragment_test.go",
"classpath_element_test.go",
+ "metadata_test.go",
"platform_bootclasspath_test.go",
"systemserver_classpath_fragment_test.go",
"vndk_test.go",
diff --git a/apex/OWNERS b/apex/OWNERS
deleted file mode 100644
index 8e4ba5c..0000000
--- a/apex/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-per-file * = jiyong@google.com
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 7babd45..684833d 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -23,8 +23,7 @@
"android/soong/android"
"android/soong/cc"
"android/soong/java"
-
- "github.com/google/blueprint/proptools"
+ "android/soong/rust"
)
func (a *apexBundle) AndroidMk() android.AndroidMkData {
@@ -64,21 +63,26 @@
}
// Return the full module name for a dependency module, which appends the apex module name unless re-using a system lib.
-func (a *apexBundle) fullModuleName(apexBundleName string, fi *apexFile) string {
- linkToSystemLib := a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform()
-
+func (a *apexBundle) fullModuleName(apexBundleName string, linkToSystemLib bool, fi *apexFile) string {
if linkToSystemLib {
return fi.androidMkModuleName
}
return fi.androidMkModuleName + "." + apexBundleName + a.suffix
}
-func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, moduleDir string,
+// androidMkForFiles generates Make definitions for the contents of an
+// apexBundle (apexBundle#filesInfo). The filesInfo structure can either be
+// populated by Soong for unconverted APEXes, or Bazel in mixed mode. Use
+// apexFile#isBazelPrebuilt to differentiate.
+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,31 +93,11 @@
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 {
linkToSystemLib := a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform()
-
- moduleName := a.fullModuleName(apexBundleName, &fi)
+ moduleName := a.fullModuleName(apexBundleName, linkToSystemLib, &fi)
// This name will be added to LOCAL_REQUIRED_MODULES of the APEX. We need to be
// arch-specific otherwise we will end up installing both ABIs even when only
@@ -141,18 +125,19 @@
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
}
fmt.Fprintln(w, "LOCAL_MODULE :=", moduleName)
+
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 +150,8 @@
}
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,
@@ -178,6 +163,7 @@
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String())
fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.nameInMake())
if fi.module != nil {
+ // This apexFile's module comes from Soong
archStr := fi.module.Target().Arch.ArchType.String()
host := false
switch fi.module.Target().Os.Class {
@@ -205,6 +191,9 @@
fmt.Fprintln(w, "LOCAL_MODULE_HOST_OS :=", makeOs)
fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
}
+ } else if fi.isBazelPrebuilt && fi.arch != "" {
+ // This apexFile comes from Bazel
+ fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", fi.arch)
}
if fi.jacocoReportClassesFile != nil {
fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", fi.jacocoReportClassesFile.String())
@@ -248,13 +237,21 @@
fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_android_app_set.mk")
case nativeSharedLib, nativeExecutable, nativeTest:
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.stem())
- if ccMod, ok := fi.module.(*cc.Module); ok {
- if ccMod.UnstrippedOutputFile() != nil {
- fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", ccMod.UnstrippedOutputFile().String())
- }
- ccMod.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
- if ccMod.CoverageOutputFile().Valid() {
- fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", ccMod.CoverageOutputFile().String())
+ if fi.isBazelPrebuilt {
+ fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", fi.unstrippedBuiltFile)
+ } else {
+ if ccMod, ok := fi.module.(*cc.Module); ok {
+ if ccMod.UnstrippedOutputFile() != nil {
+ fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", ccMod.UnstrippedOutputFile().String())
+ }
+ ccMod.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
+ 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")
@@ -320,8 +317,7 @@
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 a9c8afc..4424b22 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -50,7 +50,7 @@
ctx.RegisterModuleType("apex", BundleFactory)
ctx.RegisterModuleType("apex_test", TestApexBundleFactory)
ctx.RegisterModuleType("apex_vndk", vndkApexBundleFactory)
- ctx.RegisterModuleType("apex_defaults", defaultsFactory)
+ ctx.RegisterModuleType("apex_defaults", DefaultsFactory)
ctx.RegisterModuleType("prebuilt_apex", PrebuiltFactory)
ctx.RegisterModuleType("override_apex", OverrideApexFactory)
ctx.RegisterModuleType("apex_set", apexSetFactory)
@@ -94,15 +94,15 @@
// 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 @@
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 @@
// 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 @@
// 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
@@ -519,6 +509,21 @@
shBinary
)
+var (
+ classes = map[string]apexFileClass{
+ "app": app,
+ "appSet": appSet,
+ "etc": etc,
+ "goBinary": goBinary,
+ "javaSharedLib": javaSharedLib,
+ "nativeExecutable": nativeExecutable,
+ "nativeSharedLib": nativeSharedLib,
+ "nativeTest": nativeTest,
+ "pyBinary": pyBinary,
+ "shBinary": shBinary,
+ }
+)
+
// apexFile represents a file in an APEX bundle. This is created during the first half of
// GenerateAndroidBuildActions by traversing the dependencies of the APEX. Then in the second half
// of the function, this is used to create commands that copies the files into a staging directory,
@@ -528,6 +533,7 @@
// buildFile is put in the installDir inside the APEX.
builtFile android.Path
installDir string
+ partition string
customStem string
symlinks []string // additional symlinks
@@ -552,6 +558,10 @@
multilib string
+ isBazelPrebuilt bool
+ unstrippedBuiltFile android.Path
+ arch string
+
// TODO(jiyong): remove this
module android.Module
}
@@ -567,6 +577,7 @@
}
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 +870,10 @@
// 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 +887,6 @@
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 +1058,7 @@
// 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,
@@ -1718,6 +1729,7 @@
// NB: Since go binaries are static we don't need the module for anything here, which is
// good since the go tool is a blueprint.Module not an android.Module like we would
// normally use.
+ //
return newApexFile(ctx, fileToCopy, depName, dirInApex, goBinary, nil)
}
@@ -1781,6 +1793,18 @@
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 +1988,11 @@
}
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 +2020,45 @@
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 in mixed mode must retrieve all information about the apex's
+ // contents completely from the Starlark providers. It should never rely on
+ // Android.bp information, as they might not exist for fully migrated
+ // dependencies.
+ //
+ // 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. " +
+ "Did something else set filesInfo before this line of code?"))
+ }
+ for _, f := range outputs.PayloadFilesInfo {
+ fileInfo := apexFile{
+ isBazelPrebuilt: true,
+ builtFile: android.PathForBazelOut(ctx, f["built_file"]),
+ unstrippedBuiltFile: android.PathForBazelOut(ctx, f["unstripped_built_file"]),
+ androidMkModuleName: f["make_module_name"],
+ installDir: f["install_dir"],
+ class: classes[f["class"]],
+ customStem: f["basename"],
+ moduleDir: f["package"],
+ }
+
+ arch := f["arch"]
+ fileInfo.arch = arch
+ if len(arch) > 0 {
+ fileInfo.multilib = "lib32"
+ if strings.HasSuffix(arch, "64") {
+ fileInfo.multilib = "lib64"
+ }
+ }
+
+ a.filesInfo = append(a.filesInfo, fileInfo)
+ }
}
func (a *apexBundle) setCompression(ctx android.ModuleContext) {
@@ -2475,6 +2528,9 @@
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",
@@ -2720,14 +2776,9 @@
}
// apex_defaults provides defaultable properties to other apex modules.
-func defaultsFactory() android.Module {
- return DefaultsFactory()
-}
-
-func DefaultsFactory(props ...interface{}) android.Module {
+func DefaultsFactory() android.Module {
module := &Defaults{}
- module.AddProperties(props...)
module.AddProperties(
&apexBundleProperties{},
&apexTargetBundleProperties{},
@@ -2974,8 +3025,8 @@
if a.UsePlatformApis() {
ctx.PropertyErrorf("updatable", "updatable APEXes can't use platform APIs")
}
- if a.SocSpecific() || a.DeviceSpecific() {
- ctx.PropertyErrorf("updatable", "vendor APEXes are not updatable")
+ if proptools.Bool(a.properties.Use_vndk_as_stable) {
+ ctx.PropertyErrorf("use_vndk_as_stable", "updatable APEXes can't use external VNDK libs")
}
if a.FutureUpdatable() {
ctx.PropertyErrorf("future_updatable", "Already updatable. Remove `future_updatable: true:`")
@@ -3105,9 +3156,9 @@
// 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...)
}
@@ -3530,7 +3581,7 @@
fileContextsLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *a.properties.File_contexts))
}
- productVariableProps := android.ProductVariableProperties(ctx)
+ productVariableProps := android.ProductVariableProperties(ctx, a)
// TODO(b/219503907) this would need to be set to a.MinSdkVersionValue(ctx) but
// given it's coming via config, we probably don't want to put it in here.
var minSdkVersion bazel.StringAttribute
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index 6faed70..1581949 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -55,17 +55,17 @@
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 31e848e..e1e508b 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -784,6 +784,43 @@
}
}
+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 {
@@ -1890,13 +1927,13 @@
expectNoLink("libx", "shared_apex10000", "libz", "shared")
}
-func TestApexMinSdkVersion_crtobjectInVendorApex(t *testing.T) {
+func TestApexMinSdkVersion_InVendorApex(t *testing.T) {
ctx := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
native_shared_libs: ["mylib"],
- updatable: false,
+ updatable: true,
vendor: true,
min_sdk_version: "29",
}
@@ -1909,20 +1946,34 @@
cc_library {
name: "mylib",
+ srcs: ["mylib.cpp"],
vendor_available: true,
- system_shared_libs: [],
- stl: "none",
- apex_available: [ "myapex" ],
min_sdk_version: "29",
+ shared_libs: ["libbar"],
+ }
+
+ cc_library {
+ name: "libbar",
+ stubs: { versions: ["29", "30"] },
+ llndk: { symbol_file: "libbar.map.txt" },
}
`)
vendorVariant := "android_vendor.29_arm64_armv8-a"
- // First check that the correct variant of crtbegin_so is used.
- ldRule := ctx.ModuleForTests("mylib", vendorVariant+"_shared_apex29").Rule("ld")
- crtBegin := names(ldRule.Args["crtBegin"])
- ensureListContains(t, crtBegin, "out/soong/.intermediates/"+cc.DefaultCcCommonTestModulesDir+"crtbegin_so/"+vendorVariant+"_apex29/crtbegin_so.o")
+ mylib := ctx.ModuleForTests("mylib", vendorVariant+"_shared_myapex")
+
+ // Ensure that mylib links with "current" LLNDK
+ libFlags := names(mylib.Rule("ld").Args["libFlags"])
+ ensureListContains(t, libFlags, "out/soong/.intermediates/libbar/"+vendorVariant+"_shared_current/libbar.so")
+
+ // Ensure that mylib is targeting 29
+ ccRule := ctx.ModuleForTests("mylib", vendorVariant+"_static_apex29").Output("obj/mylib.o")
+ ensureContains(t, ccRule.Args["cFlags"], "-target aarch64-linux-android29")
+
+ // Ensure that the correct variant of crtbegin_so is used.
+ crtBegin := mylib.Rule("ld").Args["crtBegin"]
+ ensureContains(t, crtBegin, "out/soong/.intermediates/"+cc.DefaultCcCommonTestModulesDir+"crtbegin_so/"+vendorVariant+"_apex29/crtbegin_so.o")
// Ensure that the crtbegin_so used by the APEX is targeting 29
cflags := ctx.ModuleForTests("crtbegin_so", vendorVariant+"_apex29").Rule("cc").Args["cFlags"]
@@ -2128,6 +2179,34 @@
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 +3563,14 @@
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 +3588,9 @@
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 +3604,32 @@
}
}
+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 +3911,9 @@
}`+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 +4210,11 @@
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 +4239,7 @@
"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")
}
@@ -4766,6 +4823,9 @@
android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/myapex/provenance_metadata.textproto", rule.Output.String())
android.AssertStringEquals(t, "Invalid args", "myapex", rule.Args["module_name"])
android.AssertStringEquals(t, "Invalid args", "/system/apex/myapex.apex", rule.Args["install_path"])
+
+ entries := android.AndroidMkEntriesForTest(t, ctx, testingModule.Module())[0]
+ android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "prebuilt_apex", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
}
func TestPrebuiltMissingSrc(t *testing.T) {
@@ -6316,9 +6376,6 @@
apps: ["app"],
bpfs: ["bpf"],
prebuilts: ["myetc"],
- bootclasspath_fragments: ["mybootclasspath_fragment"],
- systemserverclasspath_fragments: ["mysystemserverclasspath_fragment"],
- java_libs: ["myjava_library"],
overrides: ["oldapex"],
updatable: false,
}
@@ -6329,9 +6386,6 @@
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 +6444,6 @@
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 +6478,6 @@
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 +6492,12 @@
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 +7113,10 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- shared_libs: ["myotherlib"],
+ shared_libs: [
+ "myotherlib",
+ "myotherlib_ext",
+ ],
system_shared_libs: [],
stl: "none",
apex_available: [
@@ -7168,6 +7140,20 @@
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 +7194,15 @@
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 +7216,27 @@
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) {
@@ -7881,12 +7874,14 @@
`)
}
-func TestUpdatable_cannot_be_vendor_apex(t *testing.T) {
- testApexError(t, `"myapex" .*: updatable: vendor APEXes are not updatable`, `
+func Test_use_vndk_as_stable_shouldnt_be_used_for_updatable_vendor_apexes(t *testing.T) {
+ testApexError(t, `"myapex" .*: use_vndk_as_stable: updatable APEXes can't use external VNDK libs`, `
apex {
name: "myapex",
key: "myapex.key",
updatable: true,
+ min_sdk_version: "current",
+ use_vndk_as_stable: true,
soc_specific: true,
}
@@ -7898,6 +7893,23 @@
`)
}
+func Test_use_vndk_as_stable_shouldnt_be_used_for_non_vendor_apexes(t *testing.T) {
+ testApexError(t, `"myapex" .*: use_vndk_as_stable: not supported for system/system_ext APEXes`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ updatable: false,
+ use_vndk_as_stable: true,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `)
+}
+
func TestUpdatable_should_not_set_generate_classpaths_proto(t *testing.T) {
testApexError(t, `"mysystemserverclasspathfragment" .* it must not set generate_classpaths_proto to false`, `
apex {
@@ -9561,187 +9573,188 @@
}
}
-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) {
@@ -9811,30 +9824,85 @@
apex {
name: "myapex",
key: "myapex.key",
- native_shared_libs: ["libfoo"],
+ native_shared_libs: ["libbaz"],
+ binaries: ["binfoo"],
min_sdk_version: "29",
}
apex_key {
name: "myapex.key",
}
- cc_library {
- name: "libfoo",
- shared_libs: ["libc"],
+ cc_binary {
+ name: "binfoo",
+ shared_libs: ["libbar", "libbaz", "libqux",],
apex_available: ["myapex"],
min_sdk_version: "29",
+ recovery_available: false,
+ }
+ cc_library {
+ name: "libbar",
+ srcs: ["libbar.cc"],
+ stubs: {
+ symbol_file: "libbar.map.txt",
+ versions: [
+ "29",
+ ],
+ },
+ }
+ cc_library {
+ name: "libbaz",
+ srcs: ["libbaz.cc"],
+ apex_available: ["myapex"],
+ min_sdk_version: "29",
+ stubs: {
+ symbol_file: "libbaz.map.txt",
+ versions: [
+ "29",
+ ],
+ },
}
cc_api_library {
- name: "libc",
- src: "libc.so",
+ name: "libbar",
+ src: "libbar_stub.so",
min_sdk_version: "29",
- recovery_available: true,
+ variants: ["apex.29"],
+ }
+ cc_api_variant {
+ name: "libbar",
+ variant: "apex",
+ version: "29",
+ src: "libbar_apex_29.so",
+ }
+ cc_api_library {
+ name: "libbaz",
+ src: "libbaz_stub.so",
+ min_sdk_version: "29",
+ variants: ["apex.29"],
+ }
+ cc_api_variant {
+ name: "libbaz",
+ variant: "apex",
+ version: "29",
+ src: "libbaz_apex_29.so",
+ }
+ cc_api_library {
+ name: "libqux",
+ src: "libqux_stub.so",
+ min_sdk_version: "29",
+ variants: ["apex.29"],
+ }
+ cc_api_variant {
+ name: "libqux",
+ variant: "apex",
+ version: "29",
+ src: "libqux_apex_29.so",
}
api_imports {
name: "api_imports",
- shared_libs: [
- "libc",
+ apex_shared_libs: [
+ "libbar",
+ "libbaz",
+ "libqux",
],
- header_libs: [],
}
`
result := testApex(t, bp)
@@ -9850,17 +9918,107 @@
return found
}
- libfooApexVariant := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared_apex29").Module()
- libcApexVariant := result.ModuleForTests("libc.apiimport", "android_arm64_armv8-a_shared_apex29").Module()
+ // Library defines stubs and cc_api_library should be used with cc_api_library
+ binfooApexVariant := result.ModuleForTests("binfoo", "android_arm64_armv8-a_apex29").Module()
+ libbarCoreVariant := result.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
+ libbarApiImportCoreVariant := result.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
- android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries", true, hasDep(libfooApexVariant, libcApexVariant))
+ android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries", true, hasDep(binfooApexVariant, libbarApiImportCoreVariant))
+ android.AssertBoolEquals(t, "apex variant should link against original library if exists", true, hasDep(binfooApexVariant, libbarCoreVariant))
- // libfoo core variant should be buildable in the same inner tree since
- // certain mcombo files might build system and apexes in the same inner tree
- // libfoo core variant should link against source libc
- libfooCoreVariant := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
- libcCoreVariant := result.ModuleForTests("libc.apiimport", "android_arm64_armv8-a_shared").Module()
- android.AssertBoolEquals(t, "core variant should link against source libc", true, hasDep(libfooCoreVariant, libcCoreVariant))
+ binFooCFlags := result.ModuleForTests("binfoo", "android_arm64_armv8-a_apex29").Rule("ld").Args["libFlags"]
+ android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libbar.apex.29.apiimport.so")
+ android.AssertStringDoesNotContain(t, "binfoo should not link against cc_api_library itself", binFooCFlags, "libbar.apiimport.so")
+ android.AssertStringDoesNotContain(t, "binfoo should not link against original definition", binFooCFlags, "libbar.so")
+
+ // Library defined in the same APEX should be linked with original definition instead of cc_api_library
+ libbazApexVariant := result.ModuleForTests("libbaz", "android_arm64_armv8-a_shared_apex29").Module()
+ libbazApiImportCoreVariant := result.ModuleForTests("libbaz.apiimport", "android_arm64_armv8-a_shared").Module()
+ android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries even from same APEX", true, hasDep(binfooApexVariant, libbazApiImportCoreVariant))
+ android.AssertBoolEquals(t, "apex variant should link against original library if exists", true, hasDep(binfooApexVariant, libbazApexVariant))
+
+ android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libbaz.so")
+ android.AssertStringDoesNotContain(t, "binfoo should not link against cc_api_library itself", binFooCFlags, "libbaz.apiimport.so")
+ android.AssertStringDoesNotContain(t, "binfoo should not link against original definition", binFooCFlags, "libbaz.apex.29.apiimport.so")
+
+ // cc_api_library defined without original library should be linked with cc_api_library
+ libquxApiImportApexVariant := result.ModuleForTests("libqux.apiimport", "android_arm64_armv8-a_shared").Module()
+ android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries even original library definition does not exist", true, hasDep(binfooApexVariant, libquxApiImportApexVariant))
+ android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libqux.apex.29.apiimport.so")
+}
+
+func TestPlatformBinaryBuildsAgainstApiSurfaceStubLibraries(t *testing.T) {
+ bp := `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libbar"],
+ min_sdk_version: "29",
+ }
+ apex_key {
+ name: "myapex.key",
+ }
+ cc_binary {
+ name: "binfoo",
+ shared_libs: ["libbar"],
+ recovery_available: false,
+ }
+ cc_library {
+ name: "libbar",
+ srcs: ["libbar.cc"],
+ apex_available: ["myapex"],
+ min_sdk_version: "29",
+ stubs: {
+ symbol_file: "libbar.map.txt",
+ versions: [
+ "29",
+ ],
+ },
+ }
+ cc_api_library {
+ name: "libbar",
+ src: "libbar_stub.so",
+ variants: ["apex.29"],
+ }
+ cc_api_variant {
+ name: "libbar",
+ variant: "apex",
+ version: "29",
+ src: "libbar_apex_29.so",
+ }
+ api_imports {
+ name: "api_imports",
+ apex_shared_libs: [
+ "libbar",
+ ],
+ }
+ `
+
+ result := testApex(t, bp)
+
+ hasDep := func(m android.Module, wantDep android.Module) bool {
+ t.Helper()
+ var found bool
+ result.VisitDirectDeps(m, func(dep blueprint.Module) {
+ if dep == wantDep {
+ found = true
+ }
+ })
+ return found
+ }
+
+ // Library defines stubs and cc_api_library should be used with cc_api_library
+ binfooApexVariant := result.ModuleForTests("binfoo", "android_arm64_armv8-a").Module()
+ libbarCoreVariant := result.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
+ libbarApiImportCoreVariant := result.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
+
+ android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries", true, hasDep(binfooApexVariant, libbarApiImportCoreVariant))
+ android.AssertBoolEquals(t, "apex variant should link against original library if exists", true, hasDep(binfooApexVariant, libbarCoreVariant))
+
+ binFooCFlags := result.ModuleForTests("binfoo", "android_arm64_armv8-a").Rule("ld").Args["libFlags"]
+ android.AssertStringDoesContain(t, "binfoo should link against APEX variant", binFooCFlags, "libbar.apex.29.apiimport.so")
+ android.AssertStringDoesNotContain(t, "binfoo should not link against cc_api_library itself", binFooCFlags, "libbar.apiimport.so")
+ android.AssertStringDoesNotContain(t, "binfoo should not link against original definition", binFooCFlags, "libbar.so")
}
func TestTrimmedApex(t *testing.T) {
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index af4fd9f..2ddfd03 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -530,9 +530,8 @@
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 @@
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 d28f512..a3dda83 100644
--- a/apex/bp2build.go
+++ b/apex/bp2build.go
@@ -15,16 +15,22 @@
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/bp2build_test.go b/apex/bp2build_test.go
index 2f2b61e..2a0f6e9 100644
--- a/apex/bp2build_test.go
+++ b/apex/bp2build_test.go
@@ -25,6 +25,7 @@
apex_key{
name: "foo_key",
}
+
apex {
name: "foo",
key: "foo_key",
@@ -59,6 +60,16 @@
ProvidesLibs: []string{"a", "b"},
// ApexMkInfo Starlark provider
+ PayloadFilesInfo: []map[string]string{
+ {
+ "built_file": "bazel-out/adbd",
+ "install_dir": "bin",
+ "class": "nativeExecutable",
+ "make_module_name": "adbd",
+ "basename": "adbd",
+ "package": "foo",
+ },
+ },
MakeModulesToInstall: []string{"c"}, // d deliberately omitted
},
},
@@ -68,10 +79,12 @@
m := result.ModuleForTests("foo", "android_common_foo_image").Module()
ab, ok := m.(*apexBundle)
+
if !ok {
t.Fatalf("Expected module to be an apexBundle, was not")
}
+ // TODO: refactor to android.AssertStringEquals
if w, g := "out/bazel/execroot/__main__/public_key", ab.publicKeyFile.String(); w != g {
t.Errorf("Expected public key %q, got %q", w, g)
}
@@ -120,11 +133,136 @@
if len(ab.makeModulesToInstall) != 1 && ab.makeModulesToInstall[0] != "c" {
t.Errorf("Expected makeModulesToInstall slice to only contain 'c', got %q", ab.makeModulesToInstall)
}
- if w := "LOCAL_REQUIRED_MODULES := c"; !strings.Contains(data, w) {
+ if w := "LOCAL_REQUIRED_MODULES := adbd.foo c"; !strings.Contains(data, w) {
t.Errorf("Expected %q in androidmk data, but did not find it in %q", w, data)
}
}
+func TestApexImageCreatesFilesInfoForMake(t *testing.T) {
+ bp := `
+apex_key{
+ name: "foo_key",
+}
+
+apex {
+ name: "foo",
+ key: "foo_key",
+ updatable: true,
+ min_sdk_version: "31",
+ file_contexts: ":myapex-file_contexts",
+ bazel_module: { label: "//:foo" },
+}`
+
+ outputBaseDir := "out/bazel"
+ result := android.GroupFixturePreparers(
+ prepareForApexTest,
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: outputBaseDir,
+ LabelToApexInfo: map[string]cquery.ApexInfo{
+ "//:foo": {
+ // ApexInfo Starlark provider. Necessary for the test.
+ SignedOutput: "signed_out.apex",
+ BundleKeyInfo: []string{"public_key", "private_key"},
+ ContainerKeyInfo: []string{"container_cert", "container_private"},
+
+ // ApexMkInfo Starlark provider
+ PayloadFilesInfo: []map[string]string{
+ {
+ "arch": "arm64",
+ "basename": "libcrypto.so",
+ "built_file": "bazel-out/64/libcrypto.so",
+ "class": "nativeSharedLib",
+ "install_dir": "lib64",
+ "make_module_name": "libcrypto",
+ "package": "foo/bar",
+ "unstripped_built_file": "bazel-out/64/unstripped_libcrypto.so",
+ },
+ {
+ "arch": "arm",
+ "basename": "libcrypto.so",
+ "built_file": "bazel-out/32/libcrypto.so",
+ "class": "nativeSharedLib",
+ "install_dir": "lib",
+ "make_module_name": "libcrypto",
+ "package": "foo/bar",
+ },
+ {
+ "arch": "arm64",
+ "basename": "adbd",
+ "built_file": "bazel-out/adbd",
+ "class": "nativeExecutable",
+ "install_dir": "bin",
+ "make_module_name": "adbd",
+ "package": "foo",
+ },
+ },
+ },
+ },
+ }
+ }),
+ ).RunTestWithBp(t, bp)
+
+ m := result.ModuleForTests("foo", "android_common_foo_image").Module()
+ ab, ok := m.(*apexBundle)
+
+ if !ok {
+ t.Fatalf("Expected module to be an apexBundle, was not")
+ }
+
+ expectedFilesInfo := []apexFile{
+ {
+ androidMkModuleName: "libcrypto",
+ builtFile: android.PathForTesting("out/bazel/execroot/__main__/bazel-out/64/libcrypto.so"),
+ class: nativeSharedLib,
+ customStem: "libcrypto.so",
+ installDir: "lib64",
+ moduleDir: "foo/bar",
+ arch: "arm64",
+ unstrippedBuiltFile: android.PathForTesting("out/bazel/execroot/__main__/bazel-out/64/unstripped_libcrypto.so"),
+ },
+ {
+ androidMkModuleName: "libcrypto",
+ builtFile: android.PathForTesting("out/bazel/execroot/__main__/bazel-out/32/libcrypto.so"),
+ class: nativeSharedLib,
+ customStem: "libcrypto.so",
+ installDir: "lib",
+ moduleDir: "foo/bar",
+ arch: "arm",
+ },
+ {
+ androidMkModuleName: "adbd",
+ builtFile: android.PathForTesting("out/bazel/execroot/__main__/bazel-out/adbd"),
+ class: nativeExecutable,
+ customStem: "adbd",
+ installDir: "bin",
+ moduleDir: "foo",
+ arch: "arm64",
+ },
+ }
+
+ if len(ab.filesInfo) != len(expectedFilesInfo) {
+ t.Errorf("Expected %d entries in ab.filesInfo, but got %d", len(ab.filesInfo), len(expectedFilesInfo))
+ }
+
+ for idx, f := range ab.filesInfo {
+ expected := expectedFilesInfo[idx]
+ android.AssertSame(t, "different class", expected.class, f.class)
+ android.AssertStringEquals(t, "different built file", expected.builtFile.String(), f.builtFile.String())
+ android.AssertStringEquals(t, "different custom stem", expected.customStem, f.customStem)
+ android.AssertStringEquals(t, "different install dir", expected.installDir, f.installDir)
+ android.AssertStringEquals(t, "different make module name", expected.androidMkModuleName, f.androidMkModuleName)
+ android.AssertStringEquals(t, "different moduleDir", expected.moduleDir, f.moduleDir)
+ android.AssertStringEquals(t, "different arch", expected.arch, f.arch)
+ if expected.unstrippedBuiltFile != nil {
+ if f.unstrippedBuiltFile == nil {
+ t.Errorf("expected an unstripped built file path.")
+ }
+ android.AssertStringEquals(t, "different unstripped built file", expected.unstrippedBuiltFile.String(), f.unstrippedBuiltFile.String())
+ }
+ }
+}
+
func TestCompressedApexImageInMixedBuilds(t *testing.T) {
bp := `
apex_key{
diff --git a/apex/builder.go b/apex/builder.go
index 4331d3e..ee6c473 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -241,10 +241,11 @@
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 @@
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 @@
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 @@
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 (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 @@
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 @@
// 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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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/metadata.go b/apex/metadata.go
new file mode 100644
index 0000000..b1dff3e
--- /dev/null
+++ b/apex/metadata.go
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+package apex
+
+import (
+ "encoding/json"
+
+ "github.com/google/blueprint"
+
+ "android/soong/android"
+)
+
+var (
+ mtctx = android.NewPackageContext("android/soong/multitree_apex")
+)
+
+func init() {
+ RegisterModulesSingleton(android.InitRegistrationContext)
+}
+
+func RegisterModulesSingleton(ctx android.RegistrationContext) {
+ ctx.RegisterSingletonType("apex_multitree_singleton", multitreeAnalysisSingletonFactory)
+}
+
+var PrepareForTestWithApexMultitreeSingleton = android.FixtureRegisterWithContext(RegisterModulesSingleton)
+
+func multitreeAnalysisSingletonFactory() android.Singleton {
+ return &multitreeAnalysisSingleton{}
+}
+
+type multitreeAnalysisSingleton struct {
+ multitreeApexMetadataPath android.OutputPath
+}
+
+type ApexMultitreeMetadataEntry struct {
+ // The name of the apex.
+ Name string
+
+ // TODO: Add other properties as needed.
+}
+
+type ApexMultitreeMetadata struct {
+ // Information about the installable apexes.
+ Apexes map[string]ApexMultitreeMetadataEntry
+}
+
+func (p *multitreeAnalysisSingleton) GenerateBuildActions(context android.SingletonContext) {
+ data := ApexMultitreeMetadata{
+ Apexes: make(map[string]ApexMultitreeMetadataEntry, 0),
+ }
+ context.VisitAllModules(func(module android.Module) {
+ // If this module is not being installed, ignore it.
+ if !module.Enabled() || module.IsSkipInstall() {
+ return
+ }
+ // Actual apexes provide ApexBundleInfoProvider.
+ if _, ok := context.ModuleProvider(module, ApexBundleInfoProvider).(ApexBundleInfo); !ok {
+ return
+ }
+ bundle, ok := module.(*apexBundle)
+ if ok && !bundle.testApex && !bundle.vndkApex && bundle.primaryApexType {
+ name := module.Name()
+ entry := ApexMultitreeMetadataEntry{
+ Name: name,
+ }
+ data.Apexes[name] = entry
+ }
+ })
+ p.multitreeApexMetadataPath = android.PathForOutput(context, "multitree_apex_metadata.json")
+
+ jsonStr, err := json.Marshal(data)
+ if err != nil {
+ context.Errorf(err.Error())
+ }
+ android.WriteFileRule(context, p.multitreeApexMetadataPath, string(jsonStr))
+ // This seems cleaner, but doesn't emit the phony rule in testing.
+ // context.Phony("multitree_apex_metadata", p.multitreeApexMetadataPath)
+
+ context.Build(mtctx, android.BuildParams{
+ Rule: blueprint.Phony,
+ Description: "phony rule for multitree_apex_metadata",
+ Inputs: []android.Path{p.multitreeApexMetadataPath},
+ Output: android.PathForPhony(context, "multitree_apex_metadata"),
+ })
+}
diff --git a/apex/metadata_test.go b/apex/metadata_test.go
new file mode 100644
index 0000000..f6ead42
--- /dev/null
+++ b/apex/metadata_test.go
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+package apex
+
+import (
+ "strings"
+ "testing"
+
+ "android/soong/android"
+ "android/soong/java"
+)
+
+func TestModulesSingleton(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithApexMultitreeSingleton,
+ java.PrepareForTestWithDexpreopt,
+ PrepareForTestWithApexBuildComponents,
+ java.FixtureConfigureApexBootJars("myapex:foo"),
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ ).RunTestWithBp(t, `
+ prebuilt_apex {
+ name: "myapex",
+ src: "myapex.apex",
+ exported_bootclasspath_fragments: ["mybootclasspath-fragment"],
+ }
+
+ // A prebuilt java_sdk_library_import that is not preferred by default but will be preferred
+ // because AlwaysUsePrebuiltSdks() is true.
+ java_sdk_library_import {
+ name: "foo",
+ prefer: false,
+ shared_library: false,
+ permitted_packages: ["foo"],
+ public: {
+ jars: ["sdk_library/public/foo-stubs.jar"],
+ stub_srcs: ["sdk_library/public/foo_stub_sources"],
+ current_api: "sdk_library/public/foo.txt",
+ removed_api: "sdk_library/public/foo-removed.txt",
+ sdk_version: "current",
+ },
+ apex_available: ["myapex"],
+ }
+
+ prebuilt_bootclasspath_fragment {
+ name: "mybootclasspath-fragment",
+ apex_available: [
+ "myapex",
+ ],
+ contents: [
+ "foo",
+ ],
+ hidden_api: {
+ stub_flags: "prebuilt-stub-flags.csv",
+ annotation_flags: "prebuilt-annotation-flags.csv",
+ metadata: "prebuilt-metadata.csv",
+ index: "prebuilt-index.csv",
+ all_flags: "prebuilt-all-flags.csv",
+ },
+ }
+
+ platform_bootclasspath {
+ name: "myplatform-bootclasspath",
+ fragments: [
+ {
+ apex: "myapex",
+ module:"mybootclasspath-fragment",
+ },
+ ],
+ }
+`,
+ )
+
+ outputs := result.SingletonForTests("apex_multitree_singleton").AllOutputs()
+ for _, output := range outputs {
+ testingBuildParam := result.SingletonForTests("apex_multitree_singleton").Output(output)
+ switch {
+ case strings.Contains(output, "soong/multitree_apex_metadata.json"):
+ android.AssertStringEquals(t, "Invalid build rule", "android/soong/android.writeFile", testingBuildParam.Rule.String())
+ android.AssertIntEquals(t, "Invalid input", len(testingBuildParam.Inputs), 0)
+ android.AssertStringDoesContain(t, "Invalid output path", output, "soong/multitree_apex_metadata.json")
+
+ case strings.HasSuffix(output, "multitree_apex_metadata"):
+ android.AssertStringEquals(t, "Invalid build rule", "<builtin>:phony", testingBuildParam.Rule.String())
+ android.AssertStringEquals(t, "Invalid input", testingBuildParam.Inputs[0].String(), "out/soong/multitree_apex_metadata.json")
+ android.AssertStringEquals(t, "Invalid output path", output, "multitree_apex_metadata")
+ android.AssertIntEquals(t, "Invalid args", len(testingBuildParam.Args), 0)
+ }
+ }
+}
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 0997a68..cae507e 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -35,11 +35,12 @@
blueprint.RuleParams{
Command: `rm -rf "$out" && ` +
`${extract_apks} -o "${out}" -allow-prereleased=${allow-prereleased} ` +
- `-sdk-version=${sdk-version} -abis=${abis} -screen-densities=all -extract-single ` +
+ `-sdk-version=${sdk-version} -skip-sdk-check=${skip-sdk-check} -abis=${abis} ` +
+ `-screen-densities=all -extract-single ` +
`${in}`,
CommandDeps: []string{"${extract_apks}"},
},
- "abis", "allow-prereleased", "sdk-version")
+ "abis", "allow-prereleased", "sdk-version", "skip-sdk-check")
)
type prebuilt interface {
@@ -845,6 +846,7 @@
"abis": strings.Join(abis, ","),
"allow-prereleased": strconv.FormatBool(proptools.BoolDefault(p.properties.Prerelease, defaultAllowPrerelease)),
"sdk-version": ctx.Config().PlatformSdkVersion().String(),
+ "skip-sdk-check": strconv.FormatBool(ctx.Config().IsEnvTrue("SOONG_SKIP_APPSET_SDK_CHECK")),
},
})
}
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
index d037664..f94e50f 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 @@
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 @@
],
}
+ 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 @@
}
`)
- 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 @@
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 @@
],
}
+ 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 @@
}
`)
- 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 @@
],
}
+ 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 @@
}
`)
- 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 @@
],
}
+ 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 @@
}
`)
- 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 80560cf..095e89d 100644
--- a/apex/vndk.go
+++ b/apex/vndk.go
@@ -65,10 +65,6 @@
}
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())
@@ -76,12 +72,14 @@
}
targets := mctx.MultiTargets()
- if len(targets) > 0 && apiLevel.LessThan(cc.MinApiForArch(mctx, targets[0].Arch.ArchType)) {
- // Disable VNDK apexes for VNDK versions less than the minimum supported API level for the primary
- // architecture.
+ if len(targets) > 0 && apiLevel.LessThan(cc.MinApiForArch(mctx, targets[0].Arch.ArchType)) &&
+ vndkVersion != mctx.DeviceConfig().PlatformVndkVersion() {
+ // Disable VNDK APEXes for VNDK versions less than the minimum supported API
+ // level for the primary architecture. This validation is skipped if the VNDK
+ // version matches the platform VNDK version, which can occur when the device
+ // config targets the 'current' VNDK (see `vndkVersion`).
ab.Disable()
}
-
}
}
diff --git a/bazel/Android.bp b/bazel/Android.bp
index d11c78b..4709f5c 100644
--- a/bazel/Android.bp
+++ b/bazel/Android.bp
@@ -7,6 +7,7 @@
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 80cf70a..4d39e8f 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -22,10 +22,13 @@
"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 @@
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 @@
// 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 @@
"%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 @@
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 @@
// 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 @@
// 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 @@
}
}
- 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 @@
}
}
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 @@
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 @@
// 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) 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 @@
}
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 @@
// 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)})
+ var aqueryHandler *aqueryArtifactHandler
+ {
+ eventHandler.Begin("init_handler")
+ defer eventHandler.End("init_handler")
+ aqueryHandler, err = newAqueryHandler(aqueryProto)
+ if err != nil {
+ return nil, nil, err
+ }
}
- for _, protoAction := range aqueryProto.Actions {
- var environmentVariable []KeyValuePair
- var inputDepSetIds []depsetId
- var outputIds []artifactId
- var substitutions []KeyValuePair
+ // 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 _, protoEnvironmentVariable := range protoAction.EnvironmentVariables {
- environmentVariable = append(environmentVariable, KeyValuePair{
- protoEnvironmentVariable.Key, protoEnvironmentVariable.Value,
- })
+ 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 _, 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,
- })
- }
-
- 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})
+ wg.Wait()
}
-
- for _, protoDepSetOfFiles := range aqueryProto.DepSetOfFiles {
- var directArtifactIds []artifactId
- var transitiveDepSetIds []depsetId
-
- for _, protoDirectArtifactIds := range protoDepSetOfFiles.DirectArtifactIds {
- directArtifactIds = append(directArtifactIds, artifactId(protoDirectArtifactIds))
- }
- for _, protoTransitiveDepSetIds := range protoDepSetOfFiles.TransitiveDepSetIds {
- transitiveDepSetIds = append(transitiveDepSetIds, depsetId(protoTransitiveDepSetIds))
- }
- aqueryResult.DepSetOfFiles = append(aqueryResult.DepSetOfFiles,
- depSetOfFiles{
- Id: depsetId(protoDepSetOfFiles.Id),
- DirectArtifactIds: directArtifactIds,
- TransitiveDepSetIds: transitiveDepSetIds})
-
- }
-
- 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}, 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 @@
}, 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 @@
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 @@
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 @@
}
// 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)
}
+// \->\\, $->\$, `->\`, "->\", \n->\\n, '->'"'"'
+var commandLineArgumentReplacer = strings.NewReplacer(
+ `\`, `\\`,
+ `$`, `\$`,
+ "`", "\\`",
+ `"`, `\"`,
+ "\n", "\\n",
+ `'`, `'"'"'`,
+)
+
func escapeCommandlineArgument(str string) string {
- // \->\\, $->\$, `->\`, "->\", \n->\\n, '->'"'"'
- replacer := strings.NewReplacer(
- `\`, `\\`,
- `$`, `\$`,
- "`", "\\`",
- `"`, `\"`,
- "\n", "\\n",
- `'`, `'"'"'`,
- )
- return replacer.Replace(str)
+ return commandLineArgumentReplacer.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"
-}
-
-func (a action) isSymlinkTreeAction() bool {
- return a.Mnemonic == "SymlinkTree"
-}
-
-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 @@
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 4d1503e..19a584f 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -21,8 +21,10 @@
"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 @@
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 @@
t.Error(err)
return
}
- _, _, err = AqueryBuildStatements(data)
+ _, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
assertError(t, err, "undefined outputId 3")
}
@@ -226,7 +228,7 @@
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 @@
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 @@
t.Error(err)
return
}
- _, _, err = AqueryBuildStatements(data)
+ _, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
assertError(t, err, "undefined input artifactId 3")
}
@@ -319,7 +321,7 @@
t.Error(err)
return
}
- _, _, err = AqueryBuildStatements(data)
+ _, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
assertError(t, err, "undefined path fragment id 3")
}
@@ -352,7 +354,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
t.Error(err)
return
}
- _, _, err = AqueryBuildStatements(data)
+ _, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
assertError(t, err, "undefined outputId 2")
}
@@ -1004,17 +1014,18 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 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 0000000..d7f5e64
--- /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 6654191..f74c519 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -180,7 +180,7 @@
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")
@@ -197,7 +197,7 @@
local_whole_static_libs = androidmk_info.local_whole_static_libs
local_shared_libs = androidmk_info.local_shared_libs
-return json_encode({
+return json.encode({
"OutputFiles": outputFiles,
"CcObjectFiles": ccObjectFiles,
"CcSharedLibraryFiles": sharedLibraries,
@@ -207,7 +207,7 @@
"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,7 +261,12 @@
if not mk_info:
fail("%s did not provide ApexMkInfo" % id_string)
-return json_encode({
+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,
"unsigned_output": info.unsigned_output.path,
@@ -276,6 +281,8 @@
"bundle_file": info.base_with_config_zip.path,
"installed_files": info.installed_files.path,
"make_modules_to_install": mk_info.make_modules_to_install,
+ "files_info": mk_info.files_info,
+ "tidy_files": [t for t in tidy_files],
})`
}
@@ -294,9 +301,11 @@
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"`
+ MakeModulesToInstall []string `json:"make_modules_to_install"`
+ PayloadFilesInfo []map[string]string `json:"files_info"`
}
// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
@@ -338,12 +347,18 @@
local_whole_static_libs = androidmk_info.local_whole_static_libs
local_shared_libs = androidmk_info.local_shared_libs
-return json_encode({
+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 +376,7 @@
CcAndroidMkInfo
OutputFile string
UnstrippedOutput string
+ TidyFiles []string
}
// splitOrEmpty is a modification of strings.Split() that returns an empty list
diff --git a/bazel/properties.go b/bazel/properties.go
index f4acd26..40d0ba3 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -17,6 +17,7 @@
import (
"fmt"
"path/filepath"
+ "reflect"
"regexp"
"sort"
"strings"
@@ -533,6 +534,37 @@
return result, nil
}
+// ToStringListAttribute creates a StringListAttribute from this BoolAttribute,
+// where each bool corresponds to a string list value generated by the provided
+// function.
+// TODO(b/271425661): Generalize this
+func (ba *BoolAttribute) ToStringListAttribute(valueFunc func(boolPtr *bool, axis ConfigurationAxis, config string) []string) (StringListAttribute, error) {
+ mainVal := valueFunc(ba.Value, NoConfigAxis, "")
+ if !ba.HasConfigurableValues() {
+ return MakeStringListAttribute(mainVal), nil
+ }
+
+ result := StringListAttribute{}
+ if err := ba.Collapse(); err != nil {
+ return result, err
+ }
+
+ for axis, configToBools := range ba.ConfigurableValues {
+ if len(configToBools) < 1 {
+ continue
+ }
+ for config, boolPtr := range configToBools {
+ val := valueFunc(&boolPtr, axis, config)
+ if !reflect.DeepEqual(val, mainVal) {
+ result.SetSelectValue(axis, config, val)
+ }
+ }
+ result.SetSelectValue(axis, ConditionsDefaultConfigKey, mainVal)
+ }
+
+ return result, nil
+}
+
// Collapse reduces the configurable axes of the boolean attribute to a single axis.
// This is necessary for final writing to bp2build, as a configurable boolean
// attribute can only be comprised by a single select.
diff --git a/bp2build/aar_conversion_test.go b/bp2build/aar_conversion_test.go
index 0cda5dd..6020ee5 100644
--- a/bp2build/aar_conversion_test.go
+++ b/bp2build/aar_conversion_test.go
@@ -171,3 +171,39 @@
MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
}})
}
+
+func TestConvertAndroidLibraryKotlinCflags(t *testing.T) {
+ t.Helper()
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
+ Description: "Android Library with .kt srcs and kotlincflags ",
+ ModuleTypeUnderTest: "android_library",
+ ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
+ Filesystem: map[string]string{
+ "AndroidManifest.xml": "",
+ },
+ Blueprint: `
+android_library {
+ name: "TestLib",
+ srcs: ["a.java", "b.kt"],
+ kotlincflags: ["-flag1", "-flag2"],
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget(
+ "android_library",
+ "TestLib",
+ AttrNameToString{
+ "srcs": `[
+ "a.java",
+ "b.kt",
+ ]`,
+ "kotlincflags": `[
+ "-flag1",
+ "-flag2",
+ ]`,
+ "manifest": `"AndroidManifest.xml"`,
+ "resource_files": `[]`,
+ }),
+ MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
+ }})
+}
diff --git a/bp2build/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go
index 4d18f83..ef3f124 100644
--- a/bp2build/android_app_conversion_test.go
+++ b/bp2build/android_app_conversion_test.go
@@ -306,3 +306,88 @@
}),
}})
}
+
+func TestAndroidAppKotlinCflags(t *testing.T) {
+ runAndroidAppTestCase(t, Bp2buildTestCase{
+ Description: "Android app with kotlincflags",
+ ModuleTypeUnderTest: "android_app",
+ ModuleTypeUnderTestFactory: java.AndroidAppFactory,
+ Filesystem: map[string]string{
+ "res/res.png": "",
+ },
+ Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
+android_app {
+ name: "foo",
+ srcs: ["a.java", "b.kt"],
+ certificate: ":foocert",
+ manifest: "fooManifest.xml",
+ kotlincflags: ["-flag1", "-flag2"],
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("android_library", "foo_kt", AttrNameToString{
+ "srcs": `[
+ "a.java",
+ "b.kt",
+ ]`,
+ "manifest": `"fooManifest.xml"`,
+ "resource_files": `["res/res.png"]`,
+ "kotlincflags": `[
+ "-flag1",
+ "-flag2",
+ ]`,
+ }),
+ MakeBazelTarget("android_binary", "foo", AttrNameToString{
+ "deps": `[":foo_kt"]`,
+ "certificate": `":foocert"`,
+ "manifest": `"fooManifest.xml"`,
+ }),
+ }})
+}
+
+func TestAndroidAppMinSdkProvided(t *testing.T) {
+ runAndroidAppTestCase(t, Bp2buildTestCase{
+ Description: "Android app with value for min_sdk_version",
+ ModuleTypeUnderTest: "android_app",
+ ModuleTypeUnderTestFactory: java.AndroidAppFactory,
+ Filesystem: map[string]string{},
+ Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
+android_app {
+ name: "foo",
+ sdk_version: "current",
+ min_sdk_version: "24",
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("android_binary", "foo", AttrNameToString{
+ "manifest": `"AndroidManifest.xml"`,
+ "resource_files": `[]`,
+ "manifest_values": `{
+ "minSdkVersion": "24",
+ }`,
+ }),
+ }})
+}
+
+func TestAndroidAppMinSdkDefaultToSdkVersion(t *testing.T) {
+ runAndroidAppTestCase(t, Bp2buildTestCase{
+ Description: "Android app with value for sdk_version",
+ ModuleTypeUnderTest: "android_app",
+ ModuleTypeUnderTestFactory: java.AndroidAppFactory,
+ Filesystem: map[string]string{},
+ Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
+android_app {
+ name: "foo",
+ sdk_version: "30",
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("android_binary", "foo", AttrNameToString{
+ "manifest": `"AndroidManifest.xml"`,
+ "resource_files": `[]`,
+ "manifest_values": `{
+ "minSdkVersion": "30",
+ }`,
+ }),
+ }})
+}
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index 1c0e563..03fb5d4 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -61,7 +61,10 @@
ctx.RegisterModuleType("android_app_certificate", java.AndroidAppCertificateFactory)
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
ctx.RegisterModuleType("apex", apex.BundleFactory)
+ ctx.RegisterModuleType("apex_defaults", apex.DefaultsFactory)
ctx.RegisterModuleType("prebuilt_etc", etc.PrebuiltEtcFactory)
+ ctx.RegisterModuleType("soong_config_module_type", android.SoongConfigModuleTypeFactory)
+ ctx.RegisterModuleType("soong_config_string_variable", android.SoongConfigStringVariableDummyFactory)
}
func TestApexBundleSimple(t *testing.T) {
@@ -1188,9 +1191,9 @@
"tags": `["apex_available=myapex"]`,
}),
MakeBazelTarget("cc_stub_suite", "foo_stub_libs", AttrNameToString{
- "soname": `"foo.so"`,
- "source_library": `":foo"`,
- "symbol_file": `"foo.map.txt"`,
+ "soname": `"foo.so"`,
+ "source_library_label": `"//:foo"`,
+ "symbol_file": `"foo.map.txt"`,
"versions": `[
"28",
"29",
@@ -1359,3 +1362,87 @@
}),
}})
}
+
+func TestApexBundle_overridePlusProductVars(t *testing.T) {
+ // Reproduction of b/271424349
+ // Tests that overriding an apex that uses product variables correctly copies the product var
+ // selects over to the override.
+ runOverrideApexTestCase(t, Bp2buildTestCase{
+ Description: "apex - overriding a module that uses product vars",
+ ModuleTypeUnderTest: "override_apex",
+ ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+ Blueprint: `
+soong_config_string_variable {
+ name: "library_linking_strategy",
+ values: [
+ "prefer_static",
+ ],
+}
+
+soong_config_module_type {
+ name: "library_linking_strategy_apex_defaults",
+ module_type: "apex_defaults",
+ config_namespace: "ANDROID",
+ variables: ["library_linking_strategy"],
+ properties: [
+ "manifest",
+ "min_sdk_version",
+ ],
+}
+
+library_linking_strategy_apex_defaults {
+ name: "higher_min_sdk_when_prefer_static",
+ soong_config_variables: {
+ library_linking_strategy: {
+ // Use the R min_sdk_version
+ prefer_static: {},
+ // Override the R min_sdk_version to min_sdk_version that supports dcla
+ conditions_default: {
+ min_sdk_version: "31",
+ },
+ },
+ },
+}
+
+filegroup {
+ name: "foo-file_contexts",
+ srcs: [
+ "com.android.apogee-file_contexts",
+ ],
+ bazel_module: { bp2build_available: false },
+}
+
+apex {
+ name: "foo",
+ defaults: ["higher_min_sdk_when_prefer_static"],
+ min_sdk_version: "30",
+ package_name: "pkg_name",
+ file_contexts: ":foo-file_contexts",
+}
+override_apex {
+ name: "override_foo",
+ base: ":foo",
+ package_name: "override_pkg_name",
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("apex", "foo", AttrNameToString{
+ "file_contexts": `":foo-file_contexts"`,
+ "manifest": `"apex_manifest.json"`,
+ "min_sdk_version": `select({
+ "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": "30",
+ "//conditions:default": "31",
+ })`,
+ "package_name": `"pkg_name"`,
+ }), MakeBazelTarget("apex", "override_foo", AttrNameToString{
+ "base_apex_name": `"foo"`,
+ "file_contexts": `":foo-file_contexts"`,
+ "manifest": `"apex_manifest.json"`,
+ "min_sdk_version": `select({
+ "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": "30",
+ "//conditions:default": "31",
+ })`,
+ "package_name": `"override_pkg_name"`,
+ }),
+ }})
+}
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index 86b9b27..d1dfb9d 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -17,21 +17,57 @@
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 @@
}
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 @@
// 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 6c6631a..fde9b69 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -60,6 +60,15 @@
}
}
+// PackageName returns the package of the Bazel target.
+// Defaults to root of tree.
+func (t BazelTarget) PackageName() string {
+ if t.packageName == "" {
+ return "."
+ }
+ return t.packageName
+}
+
// BazelTargets is a typedef for a slice of BazelTarget objects.
type BazelTargets []BazelTarget
@@ -227,7 +236,7 @@
// 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
@@ -337,7 +346,10 @@
return
}
- buildFileToTargets[dir] = append(buildFileToTargets[dir], targets...)
+ for _, target := range targets {
+ targetDir := target.PackageName()
+ buildFileToTargets[targetDir] = append(buildFileToTargets[targetDir], target)
+ }
})
if len(errs) > 0 {
@@ -454,7 +466,8 @@
targetName := targetNameWithVariant(ctx, m)
return BazelTarget{
- name: targetName,
+ name: targetName,
+ packageName: ctx.ModuleDir(m),
content: fmt.Sprintf(
soongModuleTargetTemplate,
targetName,
diff --git a/bp2build/bzl_conversion.go b/bp2build/bzl_conversion.go
index 992cc1c..e774fdf 100644
--- a/bp2build/bzl_conversion.go
+++ b/bp2build/bzl_conversion.go
@@ -83,7 +83,7 @@
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 @@
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 @@
}
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 fe156df..0315732 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -365,7 +365,7 @@
{
description: "nocrt: true",
soongProperty: `nocrt: true,`,
- bazelAttr: AttrNameToString{"link_crt": `False`},
+ bazelAttr: AttrNameToString{"features": `["-link_crt"]`},
},
{
description: "nocrt: false",
@@ -408,12 +408,12 @@
{
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",
@@ -868,3 +868,131 @@
},
})
}
+
+func TestCcBinaryWithThinLto(t *testing.T) {
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+ description: "cc_binary has correct features when thin LTO is enabled",
+ blueprint: `
+{rule_name} {
+ name: "foo",
+ lto: {
+ thin: true,
+ },
+}`,
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `["android_thin_lto"]`,
+ }},
+ },
+ })
+}
+
+func TestCcBinaryWithLtoNever(t *testing.T) {
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+ description: "cc_binary has correct features when LTO is explicitly disabled",
+ blueprint: `
+{rule_name} {
+ name: "foo",
+ lto: {
+ never: true,
+ },
+}`,
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `["-android_thin_lto"]`,
+ }},
+ },
+ })
+}
+
+func TestCcBinaryWithThinLtoArchSpecific(t *testing.T) {
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+ description: "cc_binary has correct features when LTO differs across arch and os variants",
+ blueprint: `
+{rule_name} {
+ name: "foo",
+ target: {
+ android: {
+ lto: {
+ thin: true,
+ },
+ },
+ },
+ arch: {
+ riscv64: {
+ lto: {
+ thin: false,
+ },
+ },
+ },
+}`,
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os_arch:android_arm": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_arm64": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86_64": ["android_thin_lto"],
+ "//conditions:default": [],
+ })`,
+ }},
+ },
+ })
+}
+
+func TestCcBinaryWithThinLtoDisabledDefaultEnabledVariant(t *testing.T) {
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+ description: "cc_binary has correct features when LTO disabled by default but enabled on a particular variant",
+ blueprint: `
+{rule_name} {
+ name: "foo",
+ lto: {
+ never: true,
+ },
+ target: {
+ android: {
+ lto: {
+ thin: true,
+ never: false,
+ },
+ },
+ },
+}`,
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["android_thin_lto"],
+ "//conditions:default": ["-android_thin_lto"],
+ })`,
+ }},
+ },
+ })
+}
+
+func TestCcBinaryWithThinLtoAndWholeProgramVtables(t *testing.T) {
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+ description: "cc_binary has correct features when thin LTO is enabled with whole_program_vtables",
+ blueprint: `
+{rule_name} {
+ name: "foo",
+ lto: {
+ thin: true,
+ },
+ whole_program_vtables: true,
+}`,
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `[
+ "android_thin_lto",
+ "android_thin_lto_whole_program_vtables",
+ ]`,
+ }},
+ },
+ })
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index c11a50d..7ea1c1c 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -1308,7 +1308,7 @@
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 @@
}
`,
ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
- "link_crt": `False`,
+ "features": `["-link_crt"]`,
"srcs": `["impl.cpp"]`,
}),
},
@@ -1375,7 +1375,13 @@
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 @@
}
`,
ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
- "srcs": `["impl.cpp"]`,
- "use_libcrt": `False`,
+ "features": `["-use_libcrt"]`,
+ "srcs": `["impl.cpp"]`,
}),
})
}
@@ -1445,8 +1451,7 @@
}
`,
ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
- "srcs": `["impl.cpp"]`,
- "use_libcrt": `True`,
+ "srcs": `["impl.cpp"]`,
}),
})
}
@@ -1475,10 +1480,10 @@
`,
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 @@
}
`,
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 @@
`,
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": [],
})`,
}),
})
@@ -2783,9 +2780,9 @@
"stubs_symbol_file": `"a.map.txt"`,
})
expectedBazelTargets = append(expectedBazelTargets, makeCcStubSuiteTargets("a", AttrNameToString{
- "soname": `"a.so"`,
- "source_library": `":a"`,
- "stubs_symbol_file": `"a.map.txt"`,
+ "soname": `"a.so"`,
+ "source_library_label": `"//foo/bar:a"`,
+ "stubs_symbol_file": `"a.map.txt"`,
"stubs_versions": `[
"28",
"29",
@@ -3038,7 +3035,7 @@
}`,
ExpectedBazelTargets: makeCcLibraryTargets("foolib", AttrNameToString{
"implementation_dynamic_deps": `select({
- "//build/bazel/rules/apex:android-in_apex": [":barlib_stub_libs_current"],
+ "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:barlib"],
"//conditions:default": [":barlib"],
})`,
"local_includes": `["."]`,
@@ -3091,8 +3088,8 @@
"//build/bazel/platforms/os:linux_musl": [":quxlib"],
"//build/bazel/platforms/os:windows": [":quxlib"],
"//build/bazel/rules/apex:android-in_apex": [
- ":barlib_stub_libs_current",
- ":quxlib_stub_libs_current",
+ "@api_surfaces//module-libapi/current:barlib",
+ "@api_surfaces//module-libapi/current:quxlib",
],
"//conditions:default": [
":barlib",
@@ -3643,8 +3640,17 @@
ModuleTypeUnderTestFactory: cc.LibraryFactory,
Blueprint: `
cc_library_static {
- name: "foo",
- srcs: ["foo.cpp"],
+ name: "foo",
+ srcs: ["foo.cpp"],
+}
+cc_library_static {
+ name: "foo-no-tidy",
+ srcs: ["foo.cpp"],
+ tidy: false,
+}
+cc_library_static {
+ name: "foo-tidy",
+ srcs: ["foo.cpp"],
tidy: true,
tidy_checks: ["check1", "check2"],
tidy_checks_as_errors: ["check1error", "check2error"],
@@ -3655,7 +3661,16 @@
MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
"local_includes": `["."]`,
"srcs": `["foo.cpp"]`,
- "tidy": `True`,
+ }),
+ MakeBazelTarget("cc_library_static", "foo-no-tidy", AttrNameToString{
+ "local_includes": `["."]`,
+ "srcs": `["foo.cpp"]`,
+ "tidy": `"never"`,
+ }),
+ MakeBazelTarget("cc_library_static", "foo-tidy", AttrNameToString{
+ "local_includes": `["."]`,
+ "srcs": `["foo.cpp"]`,
+ "tidy": `"local"`,
"tidy_checks": `[
"check1",
"check2",
@@ -4087,3 +4102,225 @@
},
})
}
+
+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": ["@api_surfaces//module-libapi/current:barlib"],
+ "//conditions:default": [":barlib"],
+ })`,
+ "dynamic_deps": `select({
+ "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:bazlib"],
+ "//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": ["@api_surfaces//module-libapi/current:barlib"],
+ "//conditions:default": [":barlib"],
+ })`,
+ "dynamic_deps": `select({
+ "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:bazlib"],
+ "//conditions:default": [":bazlib"],
+ })`,
+ "local_includes": `["."]`,
+ "tags": `["apex_available=apex_available:platform"]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryWithThinLto(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library has correct features when thin LTO is enabled",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ lto: {
+ thin: true,
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "features": `["android_thin_lto"]`,
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `["android_thin_lto"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryWithLtoNever(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library has correct features when LTO is explicitly disabled",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ lto: {
+ never: true,
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "features": `["-android_thin_lto"]`,
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `["-android_thin_lto"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryWithThinLtoArchSpecific(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library has correct features when LTO differs across arch and os variants",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ target: {
+ android: {
+ lto: {
+ thin: true,
+ },
+ },
+ },
+ arch: {
+ riscv64: {
+ lto: {
+ thin: false,
+ },
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os_arch:android_arm": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_arm64": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86_64": ["android_thin_lto"],
+ "//conditions:default": [],
+ })`}),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os_arch:android_arm": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_arm64": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86_64": ["android_thin_lto"],
+ "//conditions:default": [],
+ })`}),
+ },
+ })
+}
+
+func TestCcLibraryWithThinLtoDisabledDefaultEnabledVariant(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library has correct features when LTO disabled by default but enabled on a particular variant",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ lto: {
+ never: true,
+ },
+ target: {
+ android: {
+ lto: {
+ thin: true,
+ never: false,
+ },
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["android_thin_lto"],
+ "//conditions:default": ["-android_thin_lto"],
+ })`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["android_thin_lto"],
+ "//conditions:default": ["-android_thin_lto"],
+ })`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryWithThinLtoWholeProgramVtables(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library has correct features when thin LTO is enabled with whole_program_vtables",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ lto: {
+ thin: true,
+ },
+ whole_program_vtables: true,
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "features": `[
+ "android_thin_lto",
+ "android_thin_lto_whole_program_vtables",
+ ]`,
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `[
+ "android_thin_lto",
+ "android_thin_lto_whole_program_vtables",
+ ]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index 017df6f..b685a2c 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 @@
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 @@
`,
ExpectedBazelTargets: []string{
MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
- "link_crt": `False`,
+ "features": `["-link_crt"]`,
"srcs": `["impl.cpp"]`,
}),
},
@@ -428,7 +427,7 @@
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 @@
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"]`,
+ }),
+ },
})
}
@@ -533,9 +540,9 @@
},
Blueprint: soongCcLibraryPreamble,
ExpectedBazelTargets: []string{makeCcStubSuiteTargets("a", AttrNameToString{
- "soname": `"a.so"`,
- "source_library": `":a"`,
- "stubs_symbol_file": `"a.map.txt"`,
+ "soname": `"a.so"`,
+ "source_library_label": `"//foo/bar:a"`,
+ "stubs_symbol_file": `"a.map.txt"`,
"stubs_versions": `[
"28",
"29",
@@ -967,3 +974,133 @@
},
})
}
+
+func TestCcLibrarySharedWithThinLto(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared has correct features when thin lto is enabled",
+ Blueprint: `
+cc_library_shared {
+ name: "foo",
+ lto: {
+ thin: true,
+ },
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `["android_thin_lto"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibrarySharedWithLtoNever(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared has correct features when thin lto is enabled",
+ Blueprint: `
+cc_library_shared {
+ name: "foo",
+ lto: {
+ never: true,
+ },
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `["-android_thin_lto"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibrarySharedWithThinLtoArchSpecific(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared has correct features when LTO differs across arch and os variants",
+ Blueprint: `
+cc_library_shared {
+ name: "foo",
+ target: {
+ android: {
+ lto: {
+ thin: true,
+ },
+ },
+ },
+ arch: {
+ riscv64: {
+ lto: {
+ thin: false,
+ },
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os_arch:android_arm": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_arm64": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86_64": ["android_thin_lto"],
+ "//conditions:default": [],
+ })`}),
+ },
+ })
+}
+
+func TestCcLibrarySharedWithThinLtoDisabledDefaultEnabledVariant(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared with thin lto disabled by default but enabled on a particular variant",
+ Blueprint: `
+cc_library_shared {
+ name: "foo",
+ lto: {
+ never: true,
+ },
+ target: {
+ android: {
+ lto: {
+ thin: true,
+ never: false,
+ },
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["android_thin_lto"],
+ "//conditions:default": ["-android_thin_lto"],
+ })`,
+ }),
+ },
+ })
+}
+
+func TestCcLibrarySharedWithThinLtoAndWholeProgramVtables(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared has correct features when thin LTO is enabled with whole_program_vtables",
+ Blueprint: `
+cc_library_shared {
+ name: "foo",
+ lto: {
+ thin: true,
+ },
+ whole_program_vtables: true,
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `[
+ "android_thin_lto",
+ "android_thin_lto_whole_program_vtables",
+ ]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index d5256f6..7c18037 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1553,7 +1553,7 @@
}),
MakeBazelTarget("cc_library_static", "keep_with_stubs", AttrNameToString{
"implementation_dynamic_deps": `select({
- "//build/bazel/rules/apex:android-in_apex": [":libm_stub_libs_current"],
+ "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:libm"],
"//conditions:default": [":libm"],
})`,
"system_dynamic_deps": `[]`,
@@ -1889,3 +1889,133 @@
},
})
}
+
+func TestCcLibraryStaticWithThinLto(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static has correct features when thin lto is enabled",
+ Blueprint: `
+cc_library_static {
+ name: "foo",
+ lto: {
+ thin: true,
+ },
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+ "features": `["android_thin_lto"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryStaticWithLtoNever(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static has correct features when thin lto is enabled",
+ Blueprint: `
+cc_library_static {
+ name: "foo",
+ lto: {
+ never: true,
+ },
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+ "features": `["-android_thin_lto"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryStaticWithThinLtoArchSpecific(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static has correct features when LTO differs across arch and os variants",
+ Blueprint: `
+cc_library_static {
+ name: "foo",
+ target: {
+ android: {
+ lto: {
+ thin: true,
+ },
+ },
+ },
+ arch: {
+ riscv64: {
+ lto: {
+ thin: false,
+ },
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os_arch:android_arm": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_arm64": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86_64": ["android_thin_lto"],
+ "//conditions:default": [],
+ })`}),
+ },
+ })
+}
+
+func TestCcLibraryStaticWithThinLtoDisabledDefaultEnabledVariant(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static has correct features when LTO disabled by default but enabled on a particular variant",
+ Blueprint: `
+cc_library_static {
+ name: "foo",
+ lto: {
+ never: true,
+ },
+ target: {
+ android: {
+ lto: {
+ thin: true,
+ never: false,
+ },
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["android_thin_lto"],
+ "//conditions:default": ["-android_thin_lto"],
+ })`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryStaticWithThinLtoAndWholeProgramVtables(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static has correct features when thin lto is enabled with whole_program_vtables",
+ Blueprint: `
+cc_library_static {
+ name: "foo",
+ lto: {
+ thin: true,
+ },
+ whole_program_vtables: true,
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+ "features": `[
+ "android_thin_lto",
+ "android_thin_lto_whole_program_vtables",
+ ]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_prebuilt_library_conversion_test.go b/bp2build/cc_prebuilt_library_conversion_test.go
index 2fe158e..c5a6dfd 100644
--- a/bp2build/cc_prebuilt_library_conversion_test.go
+++ b/bp2build/cc_prebuilt_library_conversion_test.go
@@ -39,6 +39,10 @@
MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
"static_library": `"libf.so"`,
}),
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static_alwayslink", AttrNameToString{
+ "static_library": `"libf.so"`,
+ "alwayslink": "True",
+ }),
MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
"shared_library": `"libf.so"`,
}),
@@ -71,8 +75,14 @@
"//build/bazel/platforms/arch:arm": "libg.so",
"//build/bazel/platforms/arch:arm64": "libf.so",
"//conditions:default": None,
- })`,
- }),
+ })`}),
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static_alwayslink", AttrNameToString{
+ "alwayslink": "True",
+ "static_library": `select({
+ "//build/bazel/platforms/arch:arm": "libg.so",
+ "//build/bazel/platforms/arch:arm64": "libf.so",
+ "//conditions:default": None,
+ })`}),
MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
"shared_library": `select({
"//build/bazel/platforms/arch:arm": "libg.so",
@@ -109,6 +119,12 @@
"export_includes": `["testdir/1/"]`,
"export_system_includes": `["testdir/2/"]`,
}),
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static_alwayslink", AttrNameToString{
+ "static_library": `"libf.so"`,
+ "export_includes": `["testdir/1/"]`,
+ "export_system_includes": `["testdir/2/"]`,
+ "alwayslink": "True",
+ }),
// TODO(b/229374533): When fixed, update this test
MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
"shared_library": `"libf.so"`,
@@ -188,6 +204,10 @@
MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
"static_library": `"libf.so"`,
}),
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static_alwayslink", AttrNameToString{
+ "static_library": `"libf.so"`,
+ "alwayslink": "True",
+ }),
MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
"shared_library": `"libg.so"`,
}),
@@ -245,6 +265,10 @@
// makeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{
// "static_library": `"libf.so"`,
// }),
+// makeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static_always", attrNameToString{
+// "static_library": `"libf.so"`,
+// "alwayslink": "True",
+// }),
// },
// })
//}
diff --git a/bp2build/cc_prebuilt_library_static_test.go b/bp2build/cc_prebuilt_library_static_test.go
index 6116b00..17da813 100644
--- a/bp2build/cc_prebuilt_library_static_test.go
+++ b/bp2build/cc_prebuilt_library_static_test.go
@@ -39,6 +39,10 @@
MakeBazelTarget("cc_prebuilt_library_static", "libtest", AttrNameToString{
"static_library": `"libf.so"`,
}),
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest_alwayslink", AttrNameToString{
+ "static_library": `"libf.so"`,
+ "alwayslink": "True",
+ }),
},
})
}
@@ -68,8 +72,14 @@
"//build/bazel/platforms/arch:arm": "libg.so",
"//build/bazel/platforms/arch:arm64": "libf.so",
"//conditions:default": None,
- })`,
- }),
+ })`}),
+ MakeBazelTarget("cc_prebuilt_library_static", "libtest_alwayslink", AttrNameToString{
+ "alwayslink": "True",
+ "static_library": `select({
+ "//build/bazel/platforms/arch:arm": "libg.so",
+ "//build/bazel/platforms/arch:arm64": "libf.so",
+ "//conditions:default": None,
+ })`}),
},
})
}
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index 2a0a78e..8e17103 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -256,7 +256,7 @@
}
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 c43fbd8..6a39e25 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -22,7 +22,7 @@
}
// 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 @@
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 @@
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 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 b9c06bc..8c1d2ae 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -84,8 +84,10 @@
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 @@
},
{
dir: "allowlists",
+ basename: GeneratedBuildFileName,
+ },
+ {
+ dir: "allowlists",
+ basename: "env.bzl",
+ },
+ {
+ dir: "allowlists",
basename: "mixed_build_prod_allowlist.txt",
},
{
diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
index 46105c7..1b9777c 100644
--- a/bp2build/java_binary_host_conversion_test.go
+++ b/bp2build/java_binary_host_conversion_test.go
@@ -56,11 +56,9 @@
java_version: "8",
}`,
ExpectedBazelTargets: []string{
- MakeBazelTarget("java_binary", "java-binary-host-1", AttrNameToString{
- "srcs": `["a.java"]`,
- "main_class": `"com.android.test.MainClass"`,
- "deps": `["//other:jni-lib-1"]`,
- "jvm_flags": `["-Djava.library.path=$${RUNPATH}other"]`,
+ MakeBazelTarget("java_library", "java-binary-host-1_lib", AttrNameToString{
+ "srcs": `["a.java"]`,
+ "deps": `["//other:jni-lib-1"]`,
"javacopts": `[
"-Xdoclint:all/protected",
"-source 1.8 -target 1.8",
@@ -68,8 +66,15 @@
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
- })`,
- }),
+ })`}),
+ MakeBazelTarget("java_binary", "java-binary-host-1", AttrNameToString{
+ "main_class": `"com.android.test.MainClass"`,
+ "jvm_flags": `["-Djava.library.path=$${RUNPATH}other"]`,
+ "runtime_deps": `[":java-binary-host-1_lib"]`,
+ "target_compatible_with": `select({
+ "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`}),
},
})
}
@@ -122,15 +127,22 @@
}
`,
ExpectedBazelTargets: []string{
- MakeBazelTarget("java_binary", "java-binary-host-libs", AttrNameToString{
- "main_class": `"com.android.test.MainClass"`,
- "srcs": `["a.java"]`,
- "deps": `[":java-lib-dep-1-neverlink"]`,
+ MakeBazelTarget("java_library", "java-binary-host-libs_lib", AttrNameToString{
+ "srcs": `["a.java"]`,
+ "deps": `[":java-lib-dep-1-neverlink"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
})`,
}),
+ MakeBazelTarget("java_binary", "java-binary-host-libs", AttrNameToString{
+ "main_class": `"com.android.test.MainClass"`,
+ "target_compatible_with": `select({
+ "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`,
+ "runtime_deps": `[":java-binary-host-libs_lib"]`,
+ }),
},
})
}
@@ -146,7 +158,7 @@
}
`,
ExpectedBazelTargets: []string{
- MakeBazelTarget("kt_jvm_library", "java-binary-host_kt", AttrNameToString{
+ MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
"srcs": `[
"a.java",
"b.kt",
@@ -158,7 +170,7 @@
}),
MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
"main_class": `"com.android.test.MainClass"`,
- "runtime_deps": `[":java-binary-host_kt"]`,
+ "runtime_deps": `[":java-binary-host_lib"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
@@ -180,7 +192,7 @@
}
`,
ExpectedBazelTargets: []string{
- MakeBazelTarget("kt_jvm_library", "java-binary-host_kt", AttrNameToString{
+ MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
"srcs": `["a.java"]`,
"common_srcs": `["b.kt"]`,
"target_compatible_with": `select({
@@ -190,7 +202,7 @@
}),
MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
"main_class": `"com.android.test.MainClass"`,
- "runtime_deps": `[":java-binary-host_kt"]`,
+ "runtime_deps": `[":java-binary-host_lib"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
@@ -216,11 +228,16 @@
}
`,
ExpectedBazelTargets: []string{
- MakeBazelTarget("kt_jvm_library", "java-binary-host_kt", AttrNameToString{
+ MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
"srcs": `[
"a.java",
"b.kt",
]`,
+ "resources": `[
+ "res/a.res",
+ "res/dir1/b.res",
+ ]`,
+ "resource_strip_prefix": `"res"`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
@@ -228,12 +245,7 @@
}),
MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
"main_class": `"com.android.test.MainClass"`,
- "runtime_deps": `[":java-binary-host_kt"]`,
- "resources": `[
- "res/a.res",
- "res/dir1/b.res",
- ]`,
- "resource_strip_prefix": `"res"`,
+ "runtime_deps": `[":java-binary-host_lib"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
@@ -259,7 +271,7 @@
}
`,
ExpectedBazelTargets: []string{
- MakeBazelTarget("kt_jvm_library", "java-binary-host_kt", AttrNameToString{
+ MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
"srcs": `[
"a.java",
"b.kt",
@@ -275,7 +287,42 @@
}),
MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
"main_class": `"com.android.test.MainClass"`,
- "runtime_deps": `[":java-binary-host_kt"]`,
+ "runtime_deps": `[":java-binary-host_lib"]`,
+ "target_compatible_with": `select({
+ "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`,
+ }),
+ },
+ })
+}
+
+func TestJavaBinaryHostKotlinCflags(t *testing.T) {
+ runJavaBinaryHostTestCase(t, Bp2buildTestCase{
+ Description: "java_binary_host with kotlincflags",
+ Filesystem: testFs,
+ Blueprint: `java_binary_host {
+ name: "java-binary-host",
+ manifest: "test.mf",
+ srcs: ["a.kt"],
+ kotlincflags: ["-flag1", "-flag2"],
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
+ "srcs": `["a.kt"]`,
+ "kotlincflags": `[
+ "-flag1",
+ "-flag2",
+ ]`,
+ "target_compatible_with": `select({
+ "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`,
+ }),
+ MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
+ "main_class": `"com.android.test.MainClass"`,
+ "runtime_deps": `[":java-binary-host_lib"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go
index 0784f4b..e3c4857 100644
--- a/bp2build/java_library_conversion_test.go
+++ b/bp2build/java_library_conversion_test.go
@@ -673,7 +673,7 @@
func TestJavaLibraryKotlinSrcs(t *testing.T) {
runJavaLibraryTestCase(t, Bp2buildTestCase{
- Description: "java_library with kotlin srcs",
+ Description: "java_library with kotlin srcs",
Blueprint: `java_library {
name: "java-lib-1",
srcs: ["a.java", "b.java", "c.kt"],
@@ -693,9 +693,32 @@
})
}
+func TestJavaLibraryKotlincflags(t *testing.T) {
+ runJavaLibraryTestCase(t, Bp2buildTestCase{
+ Description: "java_library with kotlincfalgs",
+ Blueprint: `java_library {
+ name: "java-lib-1",
+ srcs: [ "a.kt"],
+ kotlincflags: ["-flag1", "-flag2"],
+ bazel_module: { bp2build_available: true },
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("kt_jvm_library", "java-lib-1", AttrNameToString{
+ "srcs": `["a.kt"]`,
+ "kotlincflags": `[
+ "-flag1",
+ "-flag2",
+ ]`,
+ }),
+ MakeNeverlinkDuplicateTarget("kt_jvm_library", "java-lib-1"),
+ },
+ })
+}
+
func TestJavaLibraryKotlinCommonSrcs(t *testing.T) {
runJavaLibraryTestCase(t, Bp2buildTestCase{
- Description: "java_library with kotlin common_srcs",
+ Description: "java_library with kotlin common_srcs",
Blueprint: `java_library {
name: "java-lib-1",
srcs: ["a.java", "b.java"],
@@ -755,3 +778,29 @@
},
})
}
+
+func TestJavaLibraryArchVariantSrcsWithExcludes(t *testing.T) {
+ runJavaLibraryTestCase(t, Bp2buildTestCase{
+ Description: "java_library with arch variant libs",
+ Blueprint: `java_library {
+ name: "java-lib-1",
+ srcs: ["a.java", "b.java"],
+ target: {
+ android: {
+ exclude_srcs: ["a.java"],
+ },
+ },
+ bazel_module: { bp2build_available: true },
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
+ "srcs": `["b.java"] + select({
+ "//build/bazel/platforms/os:android": [],
+ "//conditions:default": ["a.java"],
+ })`,
+ }),
+ MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
+ },
+ })
+}
diff --git a/bp2build/java_sdk_library_conversion_test.go b/bp2build/java_sdk_library_conversion_test.go
new file mode 100644
index 0000000..9ce7446
--- /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 7e29fac..a020650 100644
--- a/bp2build/metrics.go
+++ b/bp2build/metrics.go
@@ -51,7 +51,7 @@
// 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 37188f1..aac5e7d 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 @@
"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 @@
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 @@
generatedBuildFileContent = packageDefaultVisibilityRegex.ReplaceAll(generatedBuildFileContent, []byte{})
}
- outFile, err := os.Create(output)
- if err != nil {
- return err
+ newContents := generatedBuildFileContent
+ if newContents[len(newContents)-1] != '\n' {
+ newContents = append(newContents, '\n')
}
+ newContents = append(newContents, srcBuildFileContent...)
- _, err = outFile.Write(generatedBuildFileContent)
- if err != nil {
- return err
- }
-
- if generatedBuildFileContent[len(generatedBuildFileContent)-1] != '\n' {
- _, err = outFile.WriteString("\n")
- if err != nil {
- return err
- }
- }
-
- _, 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 @@
}
// 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 @@
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 @@
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 @@
// 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
}
- context.mkdirCount.Add(1)
+ 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)
+ }
+
+ // 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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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)
+ 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
+ }
+ 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)
}
- })
-}
-
-func removeParallel(path string) {
- fi, err := os.Lstat(path)
- if err != nil {
- if errors.Is(err, fs.ErrNotExist) {
- return
- }
-
- 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 @@
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 92a9bf1..ee2ab08 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -21,6 +21,7 @@
import (
"fmt"
+ "sort"
"strings"
"testing"
@@ -230,11 +231,11 @@
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)
}
@@ -263,6 +264,12 @@
t.Errorf("%s: Expected %d bazel target (%s), got %d (%s)",
description, expectedCount, expectedContents, actualCount, actualTargets)
} else {
+ sort.SliceStable(actualTargets, func(i, j int) bool {
+ return actualTargets[i].name < actualTargets[j].name
+ })
+ sort.SliceStable(expectedContents, func(i, j int) bool {
+ return getTargetName(expectedContents[i]) < getTargetName(expectedContents[j])
+ })
for i, actualTarget := range actualTargets {
if w, g := expectedContents[i], actualTarget.content; w != g {
t.Errorf(
@@ -454,7 +461,7 @@
}
}
}
- productVariableProps := android.ProductVariableProperties(ctx)
+ productVariableProps := android.ProductVariableProperties(ctx, ctx.Module())
if props, ok := productVariableProps["String_literal_prop"]; ok {
for c, p := range props {
if val, ok := p.(*string); ok {
@@ -579,7 +586,7 @@
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(
@@ -616,16 +623,18 @@
return ""
}
STUB_SUITE_ATTRS := map[string]string{
- "stubs_symbol_file": "symbol_file",
- "stubs_versions": "versions",
- "soname": "soname",
- "source_library": "source_library",
+ "stubs_symbol_file": "symbol_file",
+ "stubs_versions": "versions",
+ "soname": "soname",
+ "source_library_label": "source_library_label",
}
stubSuiteAttrs := AttrNameToString{}
for key, _ := range attrs {
if _, stubSuiteAttr := STUB_SUITE_ATTRS[key]; stubSuiteAttr {
stubSuiteAttrs[STUB_SUITE_ATTRS[key]] = attrs[key]
+ } else {
+ panic(fmt.Sprintf("unused cc_stub_suite attr %q\n", key))
}
}
return MakeBazelTarget("cc_stub_suite", name+"_stub_libs", stubSuiteAttrs)
@@ -637,3 +646,13 @@
"exports": `[":` + name + `"]`,
})
}
+
+func getTargetName(targetContent string) string {
+ data := strings.Split(targetContent, "name = \"")
+ if len(data) < 2 {
+ return ""
+ } else {
+ endIndex := strings.Index(data[1], "\"")
+ return data[1][:endIndex]
+ }
+}
diff --git a/build_test.bash b/build_test.bash
index eda4beb..defdd82 100755
--- a/build_test.bash
+++ b/build_test.bash
@@ -34,9 +34,15 @@
aosp_riscv64
)
-# To track how long we took to startup. %N isn't supported on Darwin, but
-# that's detected in the Go code, which skips calculating the startup time.
-export TRACE_BEGIN_SOONG=$(date +%s%N)
+# To track how long we took to startup.
+case $(uname -s) in
+ Darwin)
+ export TRACE_BEGIN_SOONG=`$T/prebuilts/build-tools/path/darwin-x86/date +%s%3N`
+ ;;
+ *)
+ export TRACE_BEGIN_SOONG=$(date +%s%N)
+ ;;
+esac
# Remove BUILD_NUMBER so that incremental builds on build servers don't
# re-read makefiles every time.
diff --git a/cc/OWNERS b/cc/OWNERS
index ffbf14a..c4d82d2 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 ce35b5c..980dd07 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -124,14 +124,17 @@
}
}
}
- 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 2f8ee7f..097f822 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -151,7 +151,7 @@
// 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()
@@ -512,7 +512,7 @@
}
binary.baseInstaller.subDir = "bootstrap"
}
- binary.baseInstaller.install(ctx, file)
+ binary.baseInstaller.installExecutable(ctx, file)
var preferredArchSymlinkPath android.OptionalPath
for _, symlink := range binary.symlinks {
@@ -577,18 +577,22 @@
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 @@
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 @@
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 43aff5c..2fac002 100644
--- a/cc/binary_test.go
+++ b/cc/binary_test.go
@@ -15,9 +15,10 @@
package cc
import (
- "android/soong/bazel/cquery"
"testing"
+ "android/soong/bazel/cquery"
+
"android/soong/android"
)
@@ -53,6 +54,50 @@
unStrippedFilePath := binMod.(*Module).UnstrippedOutputFile()
expectedUnStrippedFile := "outputbase/execroot/__main__/foo.unstripped"
android.AssertStringEquals(t, "Unstripped output file", expectedUnStrippedFile, unStrippedFilePath.String())
+
+ entries := android.AndroidMkEntriesForTest(t, ctx, binMod)[0]
+ android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_binary", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
+}
+
+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) {
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 6c5505a..67a697a 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -71,7 +71,7 @@
}
type tidyAttributes struct {
- Tidy *bool
+ Tidy *string
Tidy_flags []string
Tidy_checks []string
Tidy_checks_as_errors []string
@@ -82,7 +82,15 @@
func (m *Module) convertTidyAttributes(ctx android.BaseMutatorContext, moduleAttrs *tidyAttributes) {
for _, f := range m.features {
if tidy, ok := f.(*tidyFeature); ok {
- moduleAttrs.Tidy = tidy.Properties.Tidy
+ var tidyAttr *string
+ if tidy.Properties.Tidy != nil {
+ if *tidy.Properties.Tidy {
+ tidyAttr = proptools.StringPtr("local")
+ } else {
+ tidyAttr = proptools.StringPtr("never")
+ }
+ }
+ moduleAttrs.Tidy = tidyAttr
moduleAttrs.Tidy_flags = tidy.Properties.Tidy_flags
moduleAttrs.Tidy_checks = tidy.Properties.Tidy_checks
moduleAttrs.Tidy_checks_as_errors = tidy.Properties.Tidy_checks_as_errors
@@ -766,7 +774,7 @@
nativeCoverage = BoolPtr(false)
}
- productVariableProps := android.ProductVariableProperties(ctx)
+ productVariableProps := android.ProductVariableProperties(ctx, ctx.Module())
(&compilerAttrs).convertProductVariables(ctx, productVariableProps)
(&linkerAttrs).convertProductVariables(ctx, productVariableProps)
@@ -817,6 +825,7 @@
compilerAttrs.hdrs.Prepend = true
features := compilerAttrs.features.Clone().Append(linkerAttrs.features).Append(bp2buildSanitizerFeatures(ctx, module))
+ features = features.Append(bp2buildLtoFeatures(ctx, module))
features.DeduplicateAxesFromBase()
addMuslSystemDynamicDeps(ctx, linkerAttrs)
@@ -965,8 +974,6 @@
systemDynamicDeps bazel.LabelListAttribute
usedSystemDynamicDepAsDynamicDep map[string]bool
- linkCrt bazel.BoolAttribute
- useLibcrt bazel.BoolAttribute
useVersionLib bazel.BoolAttribute
linkopts bazel.StringListAttribute
additionalLinkerInputs bazel.LabelListAttribute
@@ -1082,43 +1089,13 @@
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 +1115,13 @@
}
}
+ 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 +1141,6 @@
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 +1152,49 @@
}
}
+var (
+ apiSurfaceModuleLibCurrentPackage = "@api_surfaces//" + android.ModuleLibApi.String() + "/current:"
+)
+
+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 {
+ stubLabelInApiSurfaces := bazel.Label{
+ Label: apiSurfaceModuleLibCurrentPackage + l.OriginalModuleName,
+ }
+ stubLibLabels = append(stubLibLabels, stubLabelInApiSurfaces)
+ }
+ 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 +1278,7 @@
// 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)
@@ -1273,8 +1290,10 @@
la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, toRemove)
stubsToRemove := make([]bazel.Label, 0, len(la.usedSystemDynamicDepAsDynamicDep))
for _, lib := range toRemove.Includes {
- lib.Label += stubsSuffix
- stubsToRemove = append(stubsToRemove, lib)
+ stubLabelInApiSurfaces := bazel.Label{
+ Label: apiSurfaceModuleLibCurrentPackage + lib.OriginalModuleName,
+ }
+ stubsToRemove = append(stubsToRemove, stubLabelInApiSurfaces)
}
la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.MakeLabelList(stubsToRemove))
}
@@ -1457,3 +1476,49 @@
})
return sanitizerFeatures
}
+
+func bp2buildLtoFeatures(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute {
+ lto_feature_name := "android_thin_lto"
+ ltoBoolFeatures := bazel.BoolAttribute{}
+ bp2BuildPropParseHelper(ctx, m, <OProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
+ if ltoProps, ok := props.(*LTOProperties); ok {
+ thinProp := ltoProps.Lto.Thin != nil && *ltoProps.Lto.Thin
+ thinPropSetToFalse := ltoProps.Lto.Thin != nil && !*ltoProps.Lto.Thin
+ neverProp := ltoProps.Lto.Never != nil && *ltoProps.Lto.Never
+ if thinProp {
+ ltoBoolFeatures.SetSelectValue(axis, config, BoolPtr(true))
+ return
+ }
+ if neverProp || thinPropSetToFalse {
+ if thinProp {
+ ctx.ModuleErrorf("lto.thin and lto.never are mutually exclusive but were specified together")
+ } else {
+ ltoBoolFeatures.SetSelectValue(axis, config, BoolPtr(false))
+ }
+ return
+ }
+ }
+ ltoBoolFeatures.SetSelectValue(axis, config, nil)
+ })
+
+ props := m.GetArchVariantProperties(ctx, <OProperties{})
+ ltoStringFeatures, err := ltoBoolFeatures.ToStringListAttribute(func(boolPtr *bool, axis bazel.ConfigurationAxis, config string) []string {
+ if boolPtr == nil {
+ return []string{}
+ }
+ if !*boolPtr {
+ return []string{"-" + lto_feature_name}
+ }
+ features := []string{lto_feature_name}
+ if ltoProps, ok := props[axis][config].(*LTOProperties); ok {
+ if ltoProps.Whole_program_vtables != nil && *ltoProps.Whole_program_vtables {
+ features = append(features, "android_thin_lto_whole_program_vtables")
+ }
+ }
+ return features
+ })
+ if err != nil {
+ ctx.ModuleErrorf("Error processing LTO attributes: %s", err)
+ }
+ return ltoStringFeatures
+}
diff --git a/cc/cc.go b/cc/cc.go
index c33c5e3..b029d71 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1066,6 +1066,31 @@
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 @@
}
// 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 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
+}
+
+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)
-
- bazelCtx := ctx.Config().BazelContext
- if ccInfo, err := bazelCtx.GetCcInfo(bazelModuleLabel, android.GetConfigKey(ctx)); err == nil {
- c.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles)
- }
-
c.bazelHandler.ProcessBazelQueryResponse(ctx, bazelModuleLabel)
c.Properties.SubName = GetSubnameProperty(ctx, c)
@@ -2375,6 +2416,27 @@
return nonVariantLibs, variantLibs
}
+func (c *Module) shouldUseApiSurface() bool {
+ if c.Os() == android.Android && c.Target().NativeBridge != android.NativeBridgeEnabled {
+ if GetImageVariantType(c) == vendorImageVariant || GetImageVariantType(c) == productImageVariant {
+ // LLNDK Variant
+ return true
+ }
+
+ if c.Properties.IsSdkVariant {
+ // NDK Variant
+ return true
+ }
+
+ if c.isImportedApiLibrary() {
+ // API Library should depend on API headers
+ return true
+ }
+ }
+
+ return false
+}
+
func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
if !c.Enabled() {
return
@@ -2394,7 +2456,7 @@
apiNdkLibs := []string{}
apiLateNdkLibs := []string{}
- if ctx.Os() == android.Android && c.Target().NativeBridge != android.NativeBridgeEnabled {
+ if c.shouldUseApiSurface() {
deps.SharedLibs, apiNdkLibs = rewriteLibsForApiImports(c, deps.SharedLibs, apiImportInfo.SharedLibs, ctx.Config())
deps.LateSharedLibs, apiLateNdkLibs = rewriteLibsForApiImports(c, deps.LateSharedLibs, apiImportInfo.SharedLibs, ctx.Config())
deps.SystemSharedLibs, _ = rewriteLibsForApiImports(c, deps.SystemSharedLibs, apiImportInfo.SharedLibs, ctx.Config())
@@ -2425,7 +2487,7 @@
}
// Check header lib replacement from API surface first, and then check again with VSDK
- if ctx.Os() == android.Android && c.Target().NativeBridge != android.NativeBridgeEnabled {
+ if c.shouldUseApiSurface() {
lib = GetReplaceModuleName(lib, apiImportInfo.HeaderLibs)
}
lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).HeaderLibs)
@@ -2444,20 +2506,11 @@
if c.isNDKStubLibrary() {
// NDK stubs depend on their implementation because the ABI dumps are
// generated from the implementation library.
- apiImportName := c.BaseModuleName() + multitree.GetApiImportSuffix()
- // If original library exists as imported API, set dependency on the imported library
- if actx.OtherModuleExists(apiImportName) {
- actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
- c.ImageVariation(),
- blueprint.Variation{Mutator: "link", Variation: "shared"},
- ), stubImplementation, apiImportName)
- } else {
- actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
- c.ImageVariation(),
- blueprint.Variation{Mutator: "link", Variation: "shared"},
- ), stubImplementation, c.BaseModuleName())
- }
+ actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
+ c.ImageVariation(),
+ blueprint.Variation{Mutator: "link", Variation: "shared"},
+ ), stubImplementation, c.BaseModuleName())
}
for _, lib := range deps.WholeStaticLibs {
@@ -2509,12 +2562,22 @@
}
name, version := StubsLibNameAndVersion(lib)
+ if apiLibraryName, ok := apiImportInfo.SharedLibs[name]; ok && !ctx.OtherModuleExists(name) {
+ name = apiLibraryName
+ }
sharedLibNames = append(sharedLibNames, name)
variations := []blueprint.Variation{
{Mutator: "link", Variation: "shared"},
}
- AddSharedLibDependenciesWithVersions(ctx, c, variations, depTag, name, version, false)
+
+ if _, ok := apiImportInfo.ApexSharedLibs[name]; !ok || ctx.OtherModuleExists(name) {
+ AddSharedLibDependenciesWithVersions(ctx, c, variations, depTag, name, version, false)
+ }
+
+ if apiLibraryName, ok := apiImportInfo.ApexSharedLibs[name]; ok {
+ AddSharedLibDependenciesWithVersions(ctx, c, variations, depTag, apiLibraryName, version, false)
+ }
}
for _, lib := range deps.LateStaticLibs {
@@ -2822,6 +2885,23 @@
}
}
+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,24 +2917,61 @@
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
- }
+ c.apexSdkVersion = findApexSdkVersion(ctx, apexInfo)
- 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
+ skipModuleList := map[string]bool{}
+
+ var apiImportInfo multitree.ApiImportInfo
+ hasApiImportInfo := false
+
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ if dep.Name() == "api_imports" {
+ apiImportInfo = ctx.OtherModuleProvider(dep, multitree.ApiImportsProvider).(multitree.ApiImportInfo)
+ hasApiImportInfo = true
+ }
+ })
+
+ if hasApiImportInfo {
+ targetStubModuleList := map[string]string{}
+ targetOrigModuleList := map[string]string{}
+
+ // Search for dependency which both original module and API imported library with APEX stub exists
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ depName := ctx.OtherModuleName(dep)
+ if apiLibrary, ok := apiImportInfo.ApexSharedLibs[depName]; ok {
+ targetStubModuleList[apiLibrary] = depName
+ }
+ })
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ depName := ctx.OtherModuleName(dep)
+ if origLibrary, ok := targetStubModuleList[depName]; ok {
+ targetOrigModuleList[origLibrary] = depName
+ }
+ })
+
+ // Decide which library should be used between original and API imported library
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ depName := ctx.OtherModuleName(dep)
+ if apiLibrary, ok := targetOrigModuleList[depName]; ok {
+ if ShouldUseStubForApex(ctx, dep) {
+ skipModuleList[depName] = true
+ } else {
+ skipModuleList[apiLibrary] = true
+ }
+ }
+ })
}
ctx.VisitDirectDeps(func(dep android.Module) {
depName := ctx.OtherModuleName(dep)
depTag := ctx.OtherModuleDependencyTag(dep)
+ if _, ok := skipModuleList[depName]; ok {
+ // skip this module because original module or API imported module matching with this should be used instead.
+ return
+ }
+
if depTag == android.DarwinUniversalVariantTag {
depPaths.DarwinSecondArchOutput = dep.(*Module).OutputFile()
return
@@ -3190,21 +3307,8 @@
return depPaths
}
-// ChooseStubOrImpl determines whether a given dependency should be redirected to the stub variant
-// of the dependency or not, and returns the SharedLibraryInfo and FlagExporterInfo for the right
-// dependency. The stub variant is selected when the dependency crosses a boundary where each side
-// has different level of updatability. For example, if a library foo in an APEX depends on a
-// library bar which provides stable interface and exists in the platform, foo uses the stub variant
-// of bar. If bar doesn't provide a stable interface (i.e. buildStubs() == false) or is in the
-// same APEX as foo, the non-stub variant of bar is used.
-func ChooseStubOrImpl(ctx android.ModuleContext, dep android.Module) (SharedLibraryInfo, FlagExporterInfo) {
+func ShouldUseStubForApex(ctx android.ModuleContext, dep android.Module) bool {
depName := ctx.OtherModuleName(dep)
- depTag := ctx.OtherModuleDependencyTag(dep)
- libDepTag, ok := depTag.(libraryDependencyTag)
- if !ok || !libDepTag.shared() {
- panic(fmt.Errorf("Unexpected dependency tag: %T", depTag))
- }
-
thisModule, ok := ctx.Module().(android.ApexModule)
if !ok {
panic(fmt.Errorf("Not an APEX module: %q", ctx.ModuleName()))
@@ -3219,62 +3323,93 @@
bootstrap = linkable.Bootstrap()
}
+ apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+
+ useStubs := false
+
+ if lib := moduleLibraryInterface(dep); lib.buildStubs() && useVndk { // LLNDK
+ if !apexInfo.IsForPlatform() {
+ // For platform libraries, use current version of LLNDK
+ // If this is for use_vendor apex we will apply the same rules
+ // of apex sdk enforcement below to choose right version.
+ useStubs = true
+ }
+ } else if apexInfo.IsForPlatform() || apexInfo.UsePlatformApis {
+ // If not building for APEX or the containing APEX allows the use of
+ // platform APIs, use stubs only when it is from an APEX (and not from
+ // platform) However, for host, ramdisk, vendor_ramdisk, recovery or
+ // bootstrap modules, always link to non-stub variant
+ isNotInPlatform := dep.(android.ApexModule).NotInPlatform()
+
+ isApexImportedApiLibrary := false
+
+ if cc, ok := dep.(*Module); ok {
+ if apiLibrary, ok := cc.linker.(*apiLibraryDecorator); ok {
+ if apiLibrary.hasApexStubs() {
+ isApexImportedApiLibrary = true
+ }
+ }
+ }
+
+ useStubs = (isNotInPlatform || isApexImportedApiLibrary) && !bootstrap
+
+ if useStubs {
+ // Another exception: if this module is a test for an APEX, then
+ // it is linked with the non-stub variant of a module in the APEX
+ // as if this is part of the APEX.
+ testFor := ctx.Provider(android.ApexTestForInfoProvider).(android.ApexTestForInfo)
+ for _, apexContents := range testFor.ApexContents {
+ if apexContents.DirectlyInApex(depName) {
+ useStubs = false
+ break
+ }
+ }
+ }
+ if useStubs {
+ // Yet another exception: If this module and the dependency are
+ // available to the same APEXes then skip stubs between their
+ // platform variants. This complements the test_for case above,
+ // which avoids the stubs on a direct APEX library dependency, by
+ // avoiding stubs for indirect test dependencies as well.
+ //
+ // TODO(b/183882457): This doesn't work if the two libraries have
+ // only partially overlapping apex_available. For that test_for
+ // modules would need to be split into APEX variants and resolved
+ // separately for each APEX they have access to.
+ if !isApexImportedApiLibrary && android.AvailableToSameApexes(thisModule, dep.(android.ApexModule)) {
+ useStubs = false
+ }
+ }
+ } else {
+ // If building for APEX, use stubs when the parent is in any APEX that
+ // the child is not in.
+ useStubs = !android.DirectlyInAllApexes(apexInfo, depName)
+ }
+
+ return useStubs
+}
+
+// ChooseStubOrImpl determines whether a given dependency should be redirected to the stub variant
+// of the dependency or not, and returns the SharedLibraryInfo and FlagExporterInfo for the right
+// dependency. The stub variant is selected when the dependency crosses a boundary where each side
+// has different level of updatability. For example, if a library foo in an APEX depends on a
+// library bar which provides stable interface and exists in the platform, foo uses the stub variant
+// of bar. If bar doesn't provide a stable interface (i.e. buildStubs() == false) or is in the
+// same APEX as foo, the non-stub variant of bar is used.
+func ChooseStubOrImpl(ctx android.ModuleContext, dep android.Module) (SharedLibraryInfo, FlagExporterInfo) {
+ depTag := ctx.OtherModuleDependencyTag(dep)
+ libDepTag, ok := depTag.(libraryDependencyTag)
+ if !ok || !libDepTag.shared() {
+ panic(fmt.Errorf("Unexpected dependency tag: %T", depTag))
+ }
+
sharedLibraryInfo := ctx.OtherModuleProvider(dep, SharedLibraryInfoProvider).(SharedLibraryInfo)
depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
sharedLibraryStubsInfo := ctx.OtherModuleProvider(dep, SharedLibraryStubsProvider).(SharedLibraryStubsInfo)
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if !libDepTag.explicitlyVersioned && len(sharedLibraryStubsInfo.SharedStubLibraries) > 0 {
- useStubs := false
-
- if lib := moduleLibraryInterface(dep); lib.buildStubs() && useVndk { // LLNDK
- if !apexInfo.IsForPlatform() {
- // For platform libraries, use current version of LLNDK
- // If this is for use_vendor apex we will apply the same rules
- // of apex sdk enforcement below to choose right version.
- useStubs = true
- }
- } else if apexInfo.IsForPlatform() || apexInfo.UsePlatformApis {
- // If not building for APEX or the containing APEX allows the use of
- // platform APIs, use stubs only when it is from an APEX (and not from
- // platform) However, for host, ramdisk, vendor_ramdisk, recovery or
- // bootstrap modules, always link to non-stub variant
- useStubs = dep.(android.ApexModule).NotInPlatform() && !bootstrap
- if useStubs {
- // Another exception: if this module is a test for an APEX, then
- // it is linked with the non-stub variant of a module in the APEX
- // as if this is part of the APEX.
- testFor := ctx.Provider(android.ApexTestForInfoProvider).(android.ApexTestForInfo)
- for _, apexContents := range testFor.ApexContents {
- if apexContents.DirectlyInApex(depName) {
- useStubs = false
- break
- }
- }
- }
- if useStubs {
- // Yet another exception: If this module and the dependency are
- // available to the same APEXes then skip stubs between their
- // platform variants. This complements the test_for case above,
- // which avoids the stubs on a direct APEX library dependency, by
- // avoiding stubs for indirect test dependencies as well.
- //
- // TODO(b/183882457): This doesn't work if the two libraries have
- // only partially overlapping apex_available. For that test_for
- // modules would need to be split into APEX variants and resolved
- // separately for each APEX they have access to.
- if android.AvailableToSameApexes(thisModule, dep.(android.ApexModule)) {
- useStubs = false
- }
- }
- } else {
- // If building for APEX, use stubs when the parent is in any APEX that
- // the child is not in.
- useStubs = !android.DirectlyInAllApexes(apexInfo, depName)
- }
-
// when to use (unspecified) stubs, use the latest one.
- if useStubs {
+ if ShouldUseStubForApex(ctx, dep) {
stubs := sharedLibraryStubsInfo.SharedStubLibraries
toUse := stubs[len(stubs)-1]
sharedLibraryInfo = toUse.SharedLibraryInfo
@@ -3331,7 +3466,6 @@
nonSystemVariantsExist := ccDep.HasNonSystemVariants() || isLLndk
if ccDepModule != nil {
- // TODO(ivanlozano) Support snapshots for Rust-produced C library variants.
// Use base module name for snapshots when exporting to Makefile.
if snapshotPrebuilt, ok := ccDepModule.linker.(SnapshotInterface); ok {
baseName := ccDepModule.BaseModuleName()
@@ -3736,6 +3870,7 @@
// When a vendor APEX needs a VNDK lib in it (use_vndk_as_stable: false), it should be a unique
// APEX variation. Otherwise, another vendor APEX with use_vndk_as_stable:true may use a wrong
// variation of the VNDK lib because APEX variations are merged/grouped.
+ // TODO(b/274401041) Find a way to merge APEX variations for vendor apexes.
return c.UseVndk() && c.IsVndk()
}
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 62adfd3..b02e037 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -28,6 +28,10 @@
"android/soong/bazel/cquery"
)
+func init() {
+ registerTestMutators(android.InitRegistrationContext)
+}
+
func TestMain(m *testing.M) {
os.Exit(m.Run())
}
@@ -41,6 +45,36 @@
}),
)
+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 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 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/check.go b/cc/check.go
index 3d290a9..58ff5b2 100644
--- a/cc/check.go
+++ b/cc/check.go
@@ -57,6 +57,10 @@
} else if strings.HasPrefix("../", path) {
ctx.PropertyErrorf(prop, "Path must not start with `../`: `%s`. Use include_dirs to -include from a different directory", flag)
}
+ } else if args[0] == "-mllvm" {
+ if len(args) > 2 {
+ ctx.PropertyErrorf(prop, "`-mllvm` only takes one argument: `%s`", flag)
+ }
} else if strings.HasPrefix(flag, "-D") && strings.Contains(flag, "=") {
// Do nothing in this case.
// For now, we allow space characters in -DNAME=def form to allow use cases
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index d7f9618..28f3682 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -41,6 +41,11 @@
"armv8-2a-dotprod": []string{
"-march=armv8.2-a+dotprod",
},
+ "armv9-a": []string{
+ "-march=armv8.2-a+dotprod",
+ "-mbranch-protection=standard",
+ "-fno-stack-protector",
+ },
}
arm64Ldflags = []string{
@@ -101,6 +106,7 @@
exportedVars.ExportStringListStaticVariable("Arm64Armv8ABranchProtCflags", arm64ArchVariantCflags["armv8-a-branchprot"])
exportedVars.ExportStringListStaticVariable("Arm64Armv82ACflags", arm64ArchVariantCflags["armv8-2a"])
exportedVars.ExportStringListStaticVariable("Arm64Armv82ADotprodCflags", arm64ArchVariantCflags["armv8-2a-dotprod"])
+ exportedVars.ExportStringListStaticVariable("Arm64Armv9ACflags", arm64ArchVariantCflags["armv9-a"])
exportedVars.ExportStringListStaticVariable("Arm64CortexA53Cflags", arm64CpuVariantCflags["cortex-a53"])
exportedVars.ExportStringListStaticVariable("Arm64CortexA55Cflags", arm64CpuVariantCflags["cortex-a55"])
@@ -117,6 +123,7 @@
"armv8-a-branchprot": "${config.Arm64Armv8ABranchProtCflags}",
"armv8-2a": "${config.Arm64Armv82ACflags}",
"armv8-2a-dotprod": "${config.Arm64Armv82ADotprodCflags}",
+ "armv9-a": "${config.Arm64Armv9ACflags}",
}
arm64CpuVariantCflagsVar = map[string]string{
@@ -193,6 +200,7 @@
case "armv8-a-branchprot":
case "armv8-2a":
case "armv8-2a-dotprod":
+ case "armv9-a":
// Nothing extra for armv8-a/armv8-2a
default:
panic(fmt.Sprintf("Unknown ARM architecture version: %q", arch.ArchVariant))
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 981d1ea..0704550 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -97,6 +97,15 @@
// better solution comes around. See Bug 27340895
"-D__ARM_FEATURE_LPAE=1",
},
+ "cortex-a32": []string{
+ "-mcpu=cortex-a32",
+ "-mfpu=neon-vfpv4",
+ // Fake an ARM compiler flag as these processors support LPAE which clang
+ // don't advertise.
+ // TODO This is a hack and we need to add it for each processor that supports LPAE until some
+ // better solution comes around. See Bug 27340895
+ "-D__ARM_FEATURE_LPAE=1",
+ },
"cortex-a53": []string{
"-mcpu=cortex-a53",
"-mfpu=neon-fp-armv8",
@@ -204,6 +213,7 @@
exportedVars.ExportStringListStaticVariable("ArmCortexA7Cflags", armCpuVariantCflags["cortex-a7"])
exportedVars.ExportStringListStaticVariable("ArmCortexA8Cflags", armCpuVariantCflags["cortex-a8"])
exportedVars.ExportStringListStaticVariable("ArmCortexA15Cflags", armCpuVariantCflags["cortex-a15"])
+ exportedVars.ExportStringListStaticVariable("ArmCortexA32Cflags", armCpuVariantCflags["cortex-a32"])
exportedVars.ExportStringListStaticVariable("ArmCortexA53Cflags", armCpuVariantCflags["cortex-a53"])
exportedVars.ExportStringListStaticVariable("ArmCortexA55Cflags", armCpuVariantCflags["cortex-a55"])
exportedVars.ExportStringListStaticVariable("ArmKraitCflags", armCpuVariantCflags["krait"])
@@ -224,6 +234,7 @@
"cortex-a8": "${config.ArmCortexA8Cflags}",
"cortex-a9": "${config.ArmGenericCflags}",
"cortex-a15": "${config.ArmCortexA15Cflags}",
+ "cortex-a32": "${config.ArmCortexA32Cflags}",
"cortex-a53": "${config.ArmCortexA53Cflags}",
"cortex-a53.a57": "${config.ArmCortexA53Cflags}",
"cortex-a55": "${config.ArmCortexA55Cflags}",
diff --git a/cc/config/global.go b/cc/config/global.go
index d557c0b..6b45b12 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -193,6 +193,7 @@
noOverrideGlobalCflags = []string{
"-Werror=bool-operation",
+ "-Werror=format-insufficient-args",
"-Werror=implicit-int-float-conversion",
"-Werror=int-in-bool-context",
"-Werror=int-to-pointer-cast",
@@ -207,10 +208,7 @@
"-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
@@ -236,8 +234,6 @@
// New warnings to be fixed after clang-r433403
"-Wno-error=unused-but-set-variable", // http://b/197240255
"-Wno-error=unused-but-set-parameter", // http://b/197240255
- // New warnings to be fixed after clang-r458507
- "-Wno-error=unqualified-std-cast-call", // http://b/239662094
// New warnings to be fixed after clang-r468909
"-Wno-error=deprecated-builtins", // http://b/241601211
"-Wno-error=deprecated", // in external/googletest/googletest
@@ -250,16 +246,14 @@
noOverride64GlobalCflags = []string{}
noOverrideExternalGlobalCflags = []string{
- // http://b/148815709
+ // http://b/191699019
+ "-Wno-format-insufficient-args",
"-Wno-sizeof-array-div",
- // http://b/197240255
"-Wno-unused-but-set-variable",
"-Wno-unused-but-set-parameter",
- // http://b/215753485
+ "-Wno-unqualified-std-cast-call",
"-Wno-bitwise-instead-of-logical",
- // http://b/232926688
"-Wno-misleading-indentation",
- // http://b/241941550
"-Wno-array-parameter",
}
@@ -279,7 +273,6 @@
// http://b/145211477
"-Wno-pointer-compare",
- // http://b/145211022
"-Wno-final-dtor-non-final-class",
// http://b/165945989
@@ -423,16 +416,13 @@
exportedVars.ExportStringList("CommonGlobalIncludes", commonGlobalIncludes)
pctx.PrefixedExistentPathsForSourcesVariable("CommonGlobalIncludes", "-I", commonGlobalIncludes)
- exportedVars.ExportStringStaticVariable("CLANG_DEFAULT_VERSION", ClangDefaultVersion)
- exportedVars.ExportStringStaticVariable("CLANG_DEFAULT_SHORT_VERSION", ClangDefaultShortVersion)
-
pctx.StaticVariableWithEnvOverride("ClangBase", "LLVM_PREBUILTS_BASE", ClangDefaultBase)
- pctx.StaticVariableWithEnvOverride("ClangVersion", "LLVM_PREBUILTS_VERSION", ClangDefaultVersion)
+ exportedVars.ExportStringStaticVariableWithEnvOverride("ClangVersion", "LLVM_PREBUILTS_VERSION", ClangDefaultVersion)
pctx.StaticVariable("ClangPath", "${ClangBase}/${HostPrebuiltTag}/${ClangVersion}")
pctx.StaticVariable("ClangBin", "${ClangPath}/bin")
- pctx.StaticVariableWithEnvOverride("ClangShortVersion", "LLVM_RELEASE_VERSION", ClangDefaultShortVersion)
- pctx.StaticVariable("ClangAsanLibDir", "${ClangBase}/linux-x86/${ClangVersion}/lib64/clang/${ClangShortVersion}/lib/linux")
+ exportedVars.ExportStringStaticVariableWithEnvOverride("ClangShortVersion", "LLVM_RELEASE_VERSION", ClangDefaultShortVersion)
+ 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 194b242..35c57f9 100644
--- a/cc/config/riscv64_device.go
+++ b/cc/config/riscv64_device.go
@@ -39,7 +39,9 @@
}
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/coverage.go b/cc/coverage.go
index a7356f8..c0f6973 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -219,10 +219,14 @@
return properties
}
-// Coverage is an interface for non-CC modules to implement to be mutated for coverage
-type Coverage interface {
+type UseCoverage interface {
android.Module
IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool
+}
+
+// Coverage is an interface for non-CC modules to implement to be mutated for coverage
+type Coverage interface {
+ UseCoverage
SetPreventInstall()
HideFromMake()
MarkAsCoverageVariant(bool)
@@ -261,6 +265,11 @@
m[1].(Coverage).MarkAsCoverageVariant(true)
m[1].(Coverage).EnableCoverageIfNeeded()
+ } else if cov, ok := mctx.Module().(UseCoverage); ok && cov.IsNativeCoverageNeeded(mctx) {
+ // Module itself doesn't have to have "cov" variant, but it should use "cov" variants of
+ // deps.
+ mctx.CreateVariations("cov")
+ mctx.AliasVariation("cov")
}
}
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 7113d87..7aa8b91 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -212,7 +212,7 @@
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 @@
}
// 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,59 +237,64 @@
installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
fuzzBin.binaryDecorator.baseInstaller.install(ctx, file)
- fuzzBin.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzzBin.fuzzPackagedModule.FuzzProperties.Corpus)
- builder := android.NewRuleBuilder(pctx, ctx)
- intermediateDir := android.PathForModuleOut(ctx, "corpus")
- for _, entry := range fuzzBin.fuzzPackagedModule.Corpus {
- builder.Command().Text("cp").
- Input(entry).
- Output(intermediateDir.Join(ctx, entry.Base()))
- }
- builder.Build("copy_corpus", "copy corpus")
- fuzzBin.fuzzPackagedModule.CorpusIntermediateDir = intermediateDir
-
- fuzzBin.fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzzBin.fuzzPackagedModule.FuzzProperties.Data)
- builder = android.NewRuleBuilder(pctx, ctx)
- intermediateDir = android.PathForModuleOut(ctx, "data")
- for _, entry := range fuzzBin.fuzzPackagedModule.Data {
- builder.Command().Text("cp").
- Input(entry).
- Output(intermediateDir.Join(ctx, entry.Rel()))
- }
- builder.Build("copy_data", "copy data")
- fuzzBin.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" {
- ctx.PropertyErrorf("dictionary",
- "Fuzzer dictionary %q does not have '.dict' extension",
- fuzzBin.fuzzPackagedModule.Dictionary.String())
- }
- }
-
- if fuzzBin.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
- }
+ 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(
+ 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()))
+ 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 fuzzPackagedModule.Corpus {
+ builder.Command().Text("cp").
+ Input(entry).
+ Output(intermediateDir.Join(ctx, entry.Base()))
+ }
+ builder.Build("copy_corpus", "copy corpus")
+ fuzzPackagedModule.CorpusIntermediateDir = intermediateDir
+
+ fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Data)
+ builder = android.NewRuleBuilder(pctx, ctx)
+ intermediateDir = android.PathForModuleOut(ctx, "data")
+ for _, entry := range fuzzPackagedModule.Data {
+ builder.Command().Text("cp").
+ Input(entry).
+ Output(intermediateDir.Join(ctx, entry.Rel()))
+ }
+ builder.Build("copy_data", "copy data")
+ fuzzPackagedModule.DataIntermediateDir = intermediateDir
+
+ 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",
+ fuzzPackagedModule.Dictionary.String())
+ }
+ }
+
+ if fuzzPackagedModule.FuzzProperties.Fuzz_config != nil {
+ configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json")
+ android.WriteFileRule(ctx, configPath, fuzzPackagedModule.FuzzProperties.Fuzz_config.String())
+ fuzzPackagedModule.Config = configPath
+ }
+ return fuzzPackagedModule
+}
+
func NewFuzzer(hod android.HostOrDeviceSupported) *Module {
module, binary := newBinary(hod, false)
baseInstallerPath := "fuzz"
@@ -344,7 +349,7 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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/installer.go b/cc/installer.go
index e2c0e7b..716a0df 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -100,6 +100,10 @@
installer.path = ctx.InstallFile(installer.installDir(ctx), file.Base(), file)
}
+func (installer *baseInstaller) installExecutable(ctx ModuleContext, file android.Path) {
+ installer.path = ctx.InstallExecutable(installer.installDir(ctx), file.Base(), file)
+}
+
func (installer *baseInstaller) everInstallable() bool {
// Most cc modules are installable.
return true
diff --git a/cc/library.go b/cc/library.go
index b644728..68de233 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -243,7 +243,6 @@
Local_includes bazel.StringListAttribute
Absolute_includes bazel.StringListAttribute
Linkopts bazel.StringListAttribute
- Use_libcrt bazel.BoolAttribute
Rtti bazel.BoolAttribute
Stl *string
@@ -251,7 +250,6 @@
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 @@
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 @@
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,
@@ -459,16 +454,31 @@
}
soname := m.Name() + ".so"
stubSuitesAttrs := &bazelCcStubSuiteAttributes{
- Symbol_file: compilerAttrs.stubsSymbolFile,
- Versions: compilerAttrs.stubsVersions,
- Export_includes: exportedIncludes.Includes,
- Soname: &soname,
- Source_library: *bazel.MakeLabelAttribute(":" + m.Name()),
- Deps: baseAttributes.deps,
+ Symbol_file: compilerAttrs.stubsSymbolFile,
+ Versions: compilerAttrs.stubsVersions,
+ Export_includes: exportedIncludes.Includes,
+ Soname: &soname,
+ Source_library_label: proptools.StringPtr(m.GetBazelLabel(ctx, m)),
+ Deps: baseAttributes.deps,
}
ctx.CreateBazelTargetModule(stubSuitesProps,
android.CommonAttributes{Name: m.Name() + "_stub_libs"},
stubSuitesAttrs)
+
+ // Add alias for the stub shared_library in @api_surfaces repository
+ currentModuleLibApiDir := ctx.Config().ApiSurfacesDir(android.ModuleLibApi, "current")
+ actualLabelInMainWorkspace := bazel.Label{
+ Label: fmt.Sprintf("@//%s:%s%s", ctx.ModuleDir(), m.Name(), stubsSuffix),
+ }
+ ctx.CreateBazelTargetAliasInDir(currentModuleLibApiDir, m.Name(), actualLabelInMainWorkspace)
+
+ // Add alias for headers exported by the stub library
+ headerLabelInMainWorkspace := bazel.Label{
+ // This label is generated from cc_stub_suite macro
+ Label: fmt.Sprintf("@//%s:%s_stub_libs_%s_headers", ctx.ModuleDir(), m.Name(), android.ModuleLibApi.String()),
+ }
+ headerAlias := m.Name() + "_headers"
+ ctx.CreateBazelTargetAliasInDir(currentModuleLibApiDir, headerAlias, headerLabelInMainWorkspace)
}
}
@@ -845,7 +855,11 @@
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 +895,13 @@
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 +925,12 @@
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 +1510,7 @@
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 +2894,10 @@
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 +2922,6 @@
Asflags: asFlags,
Linkopts: linkerAttrs.linkopts,
- Link_crt: linkerAttrs.linkCrt,
- Use_libcrt: linkerAttrs.useLibcrt,
Use_version_lib: linkerAttrs.useVersionLib,
Rtti: compilerAttrs.rtti,
@@ -2953,12 +2966,6 @@
tags := android.ApexAvailableTags(module)
- // This lib needs some special handling in bazel, so add this tag to the build
- // file.
- if module.Name() == "libprofile-clang-extras" {
- tags.Append(bazel.MakeStringListAttribute([]string{"NO_EXPORTING"}))
- }
-
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name(), Tags: tags}, attrs)
}
@@ -2966,13 +2973,11 @@
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 +2997,7 @@
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
@@ -3031,12 +3033,12 @@
}
type bazelCcStubSuiteAttributes struct {
- Symbol_file *string
- Versions bazel.StringListAttribute
- Export_includes bazel.StringListAttribute
- Source_library bazel.LabelAttribute
- Soname *string
- Deps bazel.LabelListAttribute
+ Symbol_file *string
+ Versions bazel.StringListAttribute
+ Export_includes bazel.StringListAttribute
+ Source_library_label *string
+ Soname *string
+ Deps bazel.LabelListAttribute
}
type bazelCcHeaderAbiCheckerAttributes struct {
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 6440ee2..1dee726 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -59,12 +59,12 @@
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 @@
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 1bcbdc5..e743bb6 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -405,7 +405,7 @@
}
// 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_stub.go b/cc/library_stub.go
index 08a5eb6..18d3f21 100644
--- a/cc/library_stub.go
+++ b/cc/library_stub.go
@@ -23,7 +23,8 @@
)
var (
- ndkVariantRegex = regexp.MustCompile("ndk\\.([a-zA-Z0-9]+)")
+ ndkVariantRegex = regexp.MustCompile("ndk\\.([a-zA-Z0-9]+)")
+ stubVariantRegex = regexp.MustCompile("apex\\.([a-zA-Z0-9]+)")
)
func init() {
@@ -60,6 +61,12 @@
variantName := BuildApiVariantName(m.BaseModuleName(), targetVariant, "")
ctx.AddDependency(m, nil, variantName)
}
+ } else if m.IsStubs() {
+ targetVariant := "apex." + m.StubsVersion()
+ if inList(targetVariant, apiLibrary.properties.Variants) {
+ variantName := BuildApiVariantName(m.BaseModuleName(), targetVariant, "")
+ ctx.AddDependency(m, nil, variantName)
+ }
}
}
@@ -153,15 +160,15 @@
in = android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), src)
}
- // LLNDK variant
- if m.UseVndk() && d.hasLLNDKStubs() {
- apiVariantModule := BuildApiVariantName(m.BaseModuleName(), "llndk", "")
+ libName := m.BaseModuleName() + multitree.GetApiImportSuffix()
+ load_cc_variant := func(apiVariantModule string) {
var mod android.Module
ctx.VisitDirectDeps(func(depMod android.Module) {
if depMod.Name() == apiVariantModule {
mod = depMod
+ libName = apiVariantModule
}
})
@@ -184,37 +191,17 @@
}
}
}
+ }
+
+ if m.UseVndk() && d.hasLLNDKStubs() {
+ // LLNDK variant
+ load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "llndk", ""))
} else if m.IsSdkVariant() {
// NDK Variant
- apiVariantModule := BuildApiVariantName(m.BaseModuleName(), "ndk", m.StubsVersion())
-
- var mod android.Module
-
- ctx.VisitDirectDeps(func(depMod android.Module) {
- if depMod.Name() == apiVariantModule {
- mod = depMod
- }
- })
-
- if mod != nil {
- variantMod, ok := mod.(*CcApiVariant)
- if ok {
- in = variantMod.Src()
-
- // Copy NDK properties to cc_api_library module
- d.libraryDecorator.flagExporter.Properties.Export_include_dirs = append(
- d.libraryDecorator.flagExporter.Properties.Export_include_dirs,
- variantMod.exportProperties.Export_include_dirs...)
-
- // Export headers as system include dirs if specified. Mostly for libc
- if Bool(variantMod.exportProperties.Export_headers_as_system) {
- d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs = append(
- d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs,
- d.libraryDecorator.flagExporter.Properties.Export_include_dirs...)
- d.libraryDecorator.flagExporter.Properties.Export_include_dirs = nil
- }
- }
- }
+ load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "ndk", m.StubsVersion()))
+ } else if m.IsStubs() {
+ // APEX Variant
+ load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "apex", m.StubsVersion()))
}
// Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
@@ -237,20 +224,58 @@
d.libraryDecorator.flagExporter.setProvider(ctx)
d.unstrippedOutputFile = in
- libName := d.libraryDecorator.getLibName(ctx) + flags.Toolchain.ShlibSuffix()
+ libName += flags.Toolchain.ShlibSuffix()
tocFile := android.PathForModuleOut(ctx, libName+".toc")
d.tocFile = android.OptionalPathForPath(tocFile)
TransformSharedObjectToToc(ctx, in, tocFile)
+ outputFile := android.PathForModuleOut(ctx, libName)
+
+ // TODO(b/270485584) This copies with a new name, just to avoid conflict with prebuilts.
+ // We can just use original input if there is any way to avoid name conflict without copy.
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Description: "API surface imported library",
+ Input: in,
+ Output: outputFile,
+ Args: map[string]string{
+ "cpFlags": "-L",
+ },
+ })
+
ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
- SharedLibrary: in,
+ SharedLibrary: outputFile,
Target: ctx.Target(),
TableOfContents: d.tocFile,
})
- return in
+ d.shareStubs(ctx)
+
+ return outputFile
+}
+
+// Share additional information about stub libraries with provider
+func (d *apiLibraryDecorator) shareStubs(ctx ModuleContext) {
+ stubs := ctx.GetDirectDepsWithTag(stubImplDepTag)
+ if len(stubs) > 0 {
+ var stubsInfo []SharedStubLibrary
+ for _, stub := range stubs {
+ stubInfo := ctx.OtherModuleProvider(stub, SharedLibraryInfoProvider).(SharedLibraryInfo)
+ flagInfo := ctx.OtherModuleProvider(stub, FlagExporterInfoProvider).(FlagExporterInfo)
+ stubsInfo = append(stubsInfo, SharedStubLibrary{
+ Version: moduleLibraryInterface(stub).stubsVersion(),
+ SharedLibraryInfo: stubInfo,
+ FlagExporterInfo: flagInfo,
+ })
+ }
+ ctx.SetProvider(SharedLibraryStubsProvider, SharedLibraryStubsInfo{
+ SharedStubLibraries: stubsInfo,
+
+ IsLLNDK: ctx.IsLlndk(),
+ })
+ }
}
func (d *apiLibraryDecorator) availableFor(what string) bool {
@@ -258,6 +283,19 @@
return true
}
+func (d *apiLibraryDecorator) hasApexStubs() bool {
+ for _, variant := range d.properties.Variants {
+ if strings.HasPrefix(variant, "apex") {
+ return true
+ }
+ }
+ return false
+}
+
+func (d *apiLibraryDecorator) hasStubsVariants() bool {
+ return d.hasApexStubs()
+}
+
func (d *apiLibraryDecorator) stubsVersions(ctx android.BaseMutatorContext) []string {
m, ok := ctx.Module().(*Module)
@@ -265,14 +303,8 @@
return nil
}
- if d.hasLLNDKStubs() && m.UseVndk() {
- // LLNDK libraries only need a single stubs variant.
- return []string{android.FutureApiLevel.String()}
- }
-
// TODO(b/244244438) Create more version information for NDK and APEX variations
// NDK variants
-
if m.IsSdkVariant() {
// TODO(b/249193999) Do not check if module has NDK stubs once all NDK cc_api_library contains ndk variant of cc_api_variant.
if d.hasNDKStubs() {
@@ -280,6 +312,17 @@
}
}
+ if d.hasLLNDKStubs() && m.UseVndk() {
+ // LLNDK libraries only need a single stubs variant.
+ return []string{android.FutureApiLevel.String()}
+ }
+
+ stubsVersions := d.getStubVersions()
+
+ if len(stubsVersions) != 0 {
+ return stubsVersions
+ }
+
if m.MinSdkVersion() == "" {
return nil
}
@@ -319,6 +362,18 @@
return ndkVersions
}
+func (d *apiLibraryDecorator) getStubVersions() []string {
+ stubVersions := []string{}
+
+ for _, variant := range d.properties.Variants {
+ if match := stubVariantRegex.FindStringSubmatch(variant); len(match) == 2 {
+ stubVersions = append(stubVersions, match[1])
+ }
+ }
+
+ return stubVersions
+}
+
// 'cc_api_headers' is similar with 'cc_api_library', but which replaces
// header libraries. The module will replace any dependencies to existing
// original header libraries.
@@ -433,7 +488,7 @@
// Implement ImageInterface to generate image variants
func (v *CcApiVariant) ImageMutatorBegin(ctx android.BaseModuleContext) {}
func (v *CcApiVariant) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
- return String(v.properties.Variant) == "ndk"
+ return inList(String(v.properties.Variant), []string{"ndk", "apex"})
}
func (v *CcApiVariant) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false }
func (v *CcApiVariant) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false }
diff --git a/cc/library_stub_test.go b/cc/library_stub_test.go
index 868447a..528577a 100644
--- a/cc/library_stub_test.go
+++ b/cc/library_stub_test.go
@@ -41,6 +41,7 @@
cc_library {
name: "libfoo",
shared_libs: ["libbar"],
+ vendor_available: true,
}
cc_library {
@@ -49,6 +50,7 @@
cc_api_library {
name: "libbar",
+ vendor_available: true,
src: "libbar.so",
}
@@ -57,7 +59,6 @@
shared_libs: [
"libbar",
],
- header_libs: [],
}
`
@@ -67,8 +68,14 @@
libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
- android.AssertBoolEquals(t, "original library should not be linked", false, hasDirectDependency(t, ctx, libfoo, libbar))
- android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+ android.AssertBoolEquals(t, "original library should be linked with non-stub variant", true, hasDirectDependency(t, ctx, libfoo, libbar))
+ android.AssertBoolEquals(t, "Stub library from API surface should be not linked with non-stub variant", false, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+
+ libfooVendor := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_shared").Module()
+ libbarApiImportVendor := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
+
+ android.AssertBoolEquals(t, "original library should not be linked", false, hasDirectDependency(t, ctx, libfooVendor, libbar))
+ android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfooVendor, libbarApiImportVendor))
}
func TestApiLibraryDoNotRequireOriginalModule(t *testing.T) {
@@ -76,11 +83,13 @@
cc_library {
name: "libfoo",
shared_libs: ["libbar"],
+ vendor: true,
}
cc_api_library {
name: "libbar",
src: "libbar.so",
+ vendor_available: true,
}
api_imports {
@@ -88,14 +97,13 @@
shared_libs: [
"libbar",
],
- header_libs: [],
}
`
ctx := prepareForCcTest.RunTestWithBp(t, bp)
- libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
- libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
+ libfoo := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_shared").Module()
+ libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
}
@@ -105,143 +113,36 @@
cc_library {
name: "libfoo",
shared_libs: ["libbar"],
+ vendor_available: true,
}
cc_library {
name: "libbar",
+ vendor_available: true,
}
cc_api_library {
name: "libbar",
src: "libbar.so",
+ vendor_available: true,
}
api_imports {
name: "api_imports",
shared_libs: [],
- header_libs: [],
}
`
ctx := prepareForCcTest.RunTestWithBp(t, bp)
- libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
- libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
- libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
+ libfoo := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_shared").Module()
+ libbar := ctx.ModuleForTests("libbar", "android_vendor.29_arm64_armv8-a_shared").Module()
+ libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
android.AssertBoolEquals(t, "original library should be linked", true, hasDirectDependency(t, ctx, libfoo, libbar))
android.AssertBoolEquals(t, "Stub library from API surface should not be linked", false, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
}
-func TestApiHeaderReplacesExistingModule(t *testing.T) {
- bp := `
- cc_library {
- name: "libfoo",
- header_libs: ["libfoo_headers"],
- }
-
- cc_api_library {
- name: "libfoo",
- header_libs: ["libfoo_headers"],
- src: "libfoo.so",
- }
-
- cc_library_headers {
- name: "libfoo_headers",
- }
-
- cc_api_headers {
- name: "libfoo_headers",
- }
-
- api_imports {
- name: "api_imports",
- shared_libs: [
- "libfoo",
- ],
- header_libs: [
- "libfoo_headers",
- ],
- }
- `
-
- ctx := prepareForCcTest.RunTestWithBp(t, bp)
-
- libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
- libfooApiImport := ctx.ModuleForTests("libfoo.apiimport", "android_arm64_armv8-a_shared").Module()
- libfooHeader := ctx.ModuleForTests("libfoo_headers", "android_arm64_armv8-a").Module()
- libfooHeaderApiImport := ctx.ModuleForTests("libfoo_headers.apiimport", "android_arm64_armv8-a").Module()
-
- android.AssertBoolEquals(t, "original header should not be used for original library", false, hasDirectDependency(t, ctx, libfoo, libfooHeader))
- android.AssertBoolEquals(t, "Header from API surface should be used for original library", true, hasDirectDependency(t, ctx, libfoo, libfooHeaderApiImport))
- android.AssertBoolEquals(t, "original header should not be used for library imported from API surface", false, hasDirectDependency(t, ctx, libfooApiImport, libfooHeader))
- android.AssertBoolEquals(t, "Header from API surface should be used for library imported from API surface", true, hasDirectDependency(t, ctx, libfooApiImport, libfooHeaderApiImport))
-}
-
-func TestApiHeadersDoNotRequireOriginalModule(t *testing.T) {
- bp := `
- cc_library {
- name: "libfoo",
- header_libs: ["libfoo_headers"],
- }
-
- cc_api_headers {
- name: "libfoo_headers",
- }
-
- api_imports {
- name: "api_imports",
- shared_libs: [
- "libfoo",
- ],
- header_libs: [
- "libfoo_headers",
- ],
- }
- `
-
- ctx := prepareForCcTest.RunTestWithBp(t, bp)
-
- libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
- libfooHeaderApiImport := ctx.ModuleForTests("libfoo_headers.apiimport", "android_arm64_armv8-a").Module()
-
- android.AssertBoolEquals(t, "Header from API surface should be used for original library", true, hasDirectDependency(t, ctx, libfoo, libfooHeaderApiImport))
-}
-
-func TestApiHeadersShouldNotReplaceWithoutApiImport(t *testing.T) {
- bp := `
- cc_library {
- name: "libfoo",
- header_libs: ["libfoo_headers"],
- }
-
- cc_library_headers {
- name: "libfoo_headers",
- }
-
- cc_api_headers {
- name: "libfoo_headers",
- }
-
- api_imports {
- name: "api_imports",
- shared_libs: [
- "libfoo",
- ],
- header_libs: [],
- }
- `
-
- ctx := prepareForCcTest.RunTestWithBp(t, bp)
-
- libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
- libfooHeader := ctx.ModuleForTests("libfoo_headers", "android_arm64_armv8-a").Module()
- libfooHeaderApiImport := ctx.ModuleForTests("libfoo_headers.apiimport", "android_arm64_armv8-a").Module()
-
- android.AssertBoolEquals(t, "original header should be used for original library", true, hasDirectDependency(t, ctx, libfoo, libfooHeader))
- android.AssertBoolEquals(t, "Header from API surface should not be used for original library", false, hasDirectDependency(t, ctx, libfoo, libfooHeaderApiImport))
-}
-
func TestExportDirFromStubLibrary(t *testing.T) {
bp := `
cc_library {
@@ -330,7 +231,7 @@
android.AssertBoolEquals(t, "Stub library variant from API surface should be linked", true, hasDirectDependency(t, ctx, libbarApiImport, libbarApiVariant))
binFooLibFlags := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Rule("ld").Args["libFlags"]
- android.AssertStringDoesContain(t, "Vendor binary should be linked with LLNDK variant source", binFooLibFlags, "libbar_llndk.so")
+ android.AssertStringDoesContain(t, "Vendor binary should be linked with LLNDK variant source", binFooLibFlags, "libbar.llndk.apiimport.so")
binFooCFlags := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Rule("cc").Args["cFlags"]
android.AssertStringDoesContain(t, "Vendor binary should include headers from the LLNDK variant source", binFooCFlags, "-Ilibbar_llndk_include")
@@ -354,6 +255,17 @@
stl: "c++_shared",
}
+ cc_binary {
+ name: "binqux",
+ srcs: ["binfoo.cc"],
+ shared_libs: ["libbar"],
+ }
+
+ cc_library {
+ name: "libbar",
+ srcs: ["libbar.cc"],
+ }
+
cc_api_library {
name: "libbar",
// TODO(b/244244438) Remove src property once all variants are implemented.
@@ -417,10 +329,14 @@
android.AssertBoolEquals(t, "Stub library from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, binbaz, libbarApiImportv29))
binFooLibFlags := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Rule("ld").Args["libFlags"]
- android.AssertStringDoesContain(t, "Binary using sdk should be linked with NDK variant source", binFooLibFlags, "libbar_ndk_29.so")
+ android.AssertStringDoesContain(t, "Binary using sdk should be linked with NDK variant source", binFooLibFlags, "libbar.ndk.29.apiimport.so")
binFooCFlags := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Rule("cc").Args["cFlags"]
android.AssertStringDoesContain(t, "Binary using sdk should include headers from the NDK variant source", binFooCFlags, "-Ilibbar_ndk_29_include")
+
+ binQux := ctx.ModuleForTests("binqux", "android_arm64_armv8-a").Module()
+ android.AssertBoolEquals(t, "NDK Stub library from API surface should not be linked with nonSdk binary", false,
+ (hasDirectDependency(t, ctx, binQux, libbarApiImportv30) || hasDirectDependency(t, ctx, binQux, libbarApiImportv29)))
}
func TestApiLibraryWithMultipleVariants(t *testing.T) {
@@ -440,6 +356,11 @@
shared_libs: ["libbar"],
}
+ cc_library {
+ name: "libbar",
+ srcs: ["libbar.cc"],
+ }
+
cc_api_library {
name: "libbar",
// TODO(b/244244438) Remove src property once all variants are implemented.
@@ -450,6 +371,9 @@
"ndk.29",
"ndk.30",
"ndk.current",
+ "apex.29",
+ "apex.30",
+ "apex.current",
],
}
@@ -479,6 +403,30 @@
cc_api_variant {
name: "libbar",
+ variant: "apex",
+ version: "29",
+ src: "libbar_apex_29.so",
+ export_include_dirs: ["libbar_apex_29_include"]
+ }
+
+ cc_api_variant {
+ name: "libbar",
+ variant: "apex",
+ version: "30",
+ src: "libbar_apex_30.so",
+ export_include_dirs: ["libbar_apex_30_include"]
+ }
+
+ cc_api_variant {
+ name: "libbar",
+ variant: "apex",
+ version: "current",
+ src: "libbar_apex_current.so",
+ export_include_dirs: ["libbar_apex_current_include"]
+ }
+
+ cc_api_variant {
+ name: "libbar",
variant: "llndk",
src: "libbar_llndk.so",
export_include_dirs: ["libbar_llndk_include"]
@@ -489,7 +437,9 @@
shared_libs: [
"libbar",
],
- header_libs: [],
+ apex_shared_libs: [
+ "libbar",
+ ],
}
`
ctx := prepareForCcTest.RunTestWithBp(t, bp)
diff --git a/cc/library_test.go b/cc/library_test.go
index dab5bb8..dbe2be8 100644
--- a/cc/library_test.go
+++ b/cc/library_test.go
@@ -308,6 +308,75 @@
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,60 @@
}
+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)
+ android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_library_shared", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
+}
+
func TestCcLibrarySharedWithBazel(t *testing.T) {
t.Parallel()
bp := `
@@ -388,6 +511,7 @@
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)
+ android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_library_shared", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
}
func TestWholeStaticLibPrebuilts(t *testing.T) {
diff --git a/cc/linkable.go b/cc/linkable.go
index 0522fc6..9578807 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -3,6 +3,7 @@
import (
"android/soong/android"
"android/soong/bazel/cquery"
+ "android/soong/fuzz"
"android/soong/snapshot"
"github.com/google/blueprint"
@@ -120,6 +121,17 @@
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 @@
// 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 371d78d..e49b97d 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -237,29 +237,14 @@
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 {
+ // 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) 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) 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 @@
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 @@
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 fbd91be..4220f32 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 @@
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 a90c48c..0000000
--- 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 11ce793..ef44467 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -54,12 +54,12 @@
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 9e62bf8..5b7ba43 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -352,6 +352,7 @@
Static_library bazel.LabelAttribute
Export_includes bazel.StringListAttribute
Export_system_includes bazel.StringListAttribute
+ Alwayslink bazel.BoolAttribute
}
// TODO(b/228623543): The below is not entirely true until the bug is fixed. For now, both targets are always generated
@@ -389,6 +390,11 @@
tags := android.ApexAvailableTags(module)
ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: name, Tags: tags}, attrs, prebuiltAttrs.Enabled)
+
+ _true := true
+ alwayslinkAttrs := *attrs
+ alwayslinkAttrs.Alwayslink.SetValue(&_true)
+ ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: name + "_alwayslink", Tags: tags}, &alwayslinkAttrs, prebuiltAttrs.Enabled)
}
type bazelPrebuiltLibrarySharedAttributes struct {
@@ -488,13 +494,17 @@
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()
+ h.module.outputFile = android.OptionalPathForPath(outputPath)
+
+ depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(outputPath).Build()
ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
- StaticLibrary: out,
-
+ StaticLibrary: outputPath,
TransitiveStaticLibrariesForOrdering: depSet,
})
@@ -518,21 +528,26 @@
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 +767,12 @@
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 95fa99e..e3ec9d5 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -169,6 +169,11 @@
if !hasDep(crtx, prebuiltCrtx) {
t.Errorf("crtx missing dependency on prebuilt_crtx")
}
+
+ entries := android.AndroidMkEntriesForTest(t, ctx, prebuiltLiba)[0]
+ android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_prebuilt_library_shared", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
+ entries = android.AndroidMkEntriesForTest(t, ctx, prebuiltLibb)[0]
+ android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_prebuilt_library_static", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
}
func TestPrebuiltLibraryShared(t *testing.T) {
@@ -443,6 +448,75 @@
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 a31a358..c899cc4 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -77,7 +77,7 @@
"-fno-sanitize-recover=integer,undefined"}
hwasanGlobalOptions = []string{"heap_history_size=1023", "stack_history_size=512",
"export_memory_stats=0", "max_malloc_fill_size=131072", "malloc_fill_byte=0"}
- memtagStackCommonFlags = []string{"-march=armv8-a+memtag"}
+ memtagStackCommonFlags = []string{"-march=armv8-a+memtag", "-mllvm", "-dom-tree-reachability-max-bbs-to-explore=128"}
hostOnlySanitizeFlags = []string{"-fno-sanitize-recover=all"}
deviceOnlySanitizeFlags = []string{"-fsanitize-trap=all", "-ftrap-function=abort"}
@@ -1716,9 +1716,9 @@
// 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 3e50c9f..4f361eb 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -47,33 +47,41 @@
// 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() {
apiLibrary, _ := ccModule.linker.(*apiLibraryDecorator)
if apiLibrary.hasNDKStubs() && ccModule.canUseSdk() {
+ variations := []string{"sdk"}
+ if apiLibrary.hasApexStubs() {
+ variations = append(variations, "")
+ }
// Handle cc_api_library module with NDK stubs and variants only which can use SDK
- modules := ctx.CreateVariations("", "sdk")
- modules[1].(*Module).Properties.IsSdkVariant = true
+ modules := ctx.CreateVariations(variations...)
+ // Mark the SDK variant.
+ modules[0].(*Module).Properties.IsSdkVariant = 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
+ if apiLibrary.hasApexStubs() {
+ // For an unbundled apps build, hide the platform variant from Make.
+ modules[1].(*Module).Properties.HideFromMake = true
+ modules[1].(*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
+ modules[0].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
+ // SDK variant is not supposed to be installed
+ modules[0].(*Module).Properties.PreventInstall = true
}
} else {
ccModule.Properties.Sdk_version = nil
diff --git a/cc/sdk_test.go b/cc/sdk_test.go
index 61925e3..790440c 100644
--- a/cc/sdk_test.go
+++ b/cc/sdk_test.go
@@ -101,3 +101,95 @@
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/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index 32878ca..bb6e257 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -522,6 +522,8 @@
return false
}
+var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil)
+
func (p *snapshotLibraryDecorator) isSanitizerAvailable(t SanitizerType) bool {
switch t {
case cfi:
@@ -644,8 +646,6 @@
return module.Init()
}
-var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil)
-
// Module definitions for snapshots of executable binaries.
//
// Modules (vendor|recovery)_snapshot_binary are defined here. They have their prebuilt executable
diff --git a/cc/stub_library.go b/cc/stub_library.go
index 76da782..f324dcc 100644
--- a/cc/stub_library.go
+++ b/cc/stub_library.go
@@ -73,7 +73,7 @@
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 5c4d548..27de06b 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -649,7 +649,11 @@
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 4e10037..aa0f6b5 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -118,7 +118,7 @@
// ...
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 6ab4734..3b7c87d 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -876,7 +876,7 @@
})
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/extract_apks/main.go b/cmd/extract_apks/main.go
index 82db634..2e71fe1 100644
--- a/cmd/extract_apks/main.go
+++ b/cmd/extract_apks/main.go
@@ -41,6 +41,7 @@
abis map[android_bundle_proto.Abi_AbiAlias]int
allowPrereleased bool
stem string
+ skipSdkCheck bool
}
// An APK set is a zip archive. An entry 'toc.pb' describes its contents.
@@ -322,6 +323,12 @@
func (m sdkVersionTargetingMatcher) matches(config TargetConfig) bool {
const preReleaseVersion = 10000
+ // TODO (b274518686) This check should only be used while SHA based targeting is active
+ // Once we have switched to an SDK version, this can be changed to throw an error if
+ // it was accidentally set
+ if config.skipSdkCheck == true {
+ return true
+ }
if m.SdkVersionTargeting == nil {
return true
}
@@ -572,7 +579,7 @@
func processArgs() {
flag.Usage = func() {
fmt.Fprintln(os.Stderr, `usage: extract_apks -o <output-file> [-zip <output-zip-file>] `+
- `-sdk-version value -abis value `+
+ `-sdk-version value -abis value [-skip-sdk-check]`+
`-screen-densities value {-stem value | -extract-single} [-allow-prereleased] `+
`[-apkcerts <apkcerts output file> -partition <partition>] <APK set>`)
flag.PrintDefaults()
@@ -585,6 +592,7 @@
"'all' or comma-separated list of screen density names (NODPI LDPI MDPI TVDPI HDPI XHDPI XXHDPI XXXHDPI)")
flag.BoolVar(&targetConfig.allowPrereleased, "allow-prereleased", false,
"allow prereleased")
+ flag.BoolVar(&targetConfig.skipSdkCheck, "skip-sdk-check", false, "Skip the SDK version check")
flag.StringVar(&targetConfig.stem, "stem", "", "output entries base name in the output zip file")
flag.Parse()
if (*outputFile == "") || len(flag.Args()) != 1 || *version == 0 ||
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 0115f4a..0212075 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -515,7 +515,8 @@
"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 29a6f95..3a4d71a 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -78,9 +78,11 @@
flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output")
flag.StringVar(&cmdlineArgs.BazelForceEnabledModules, "bazel-force-enabled-modules", "", "additional modules to build with Bazel. Comma-delimited")
flag.BoolVar(&cmdlineArgs.EmptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
+ flag.BoolVar(&cmdlineArgs.MultitreeBuild, "multitree-build", false, "this is a multitree build")
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
@@ -135,7 +137,7 @@
ctx.EventHandler.Begin("queryview")
defer ctx.EventHandler.End("queryview")
codegenContext := bp2build.NewCodegenContext(ctx.Config(), ctx, bp2build.QueryView, topDir)
- err := createBazelWorkspace(codegenContext, shared.JoinPath(topDir, queryviewDir))
+ err := createBazelWorkspace(codegenContext, shared.JoinPath(topDir, queryviewDir), false)
maybeQuit(err, "")
touch(shared.JoinPath(topDir, queryviewMarker))
}
@@ -173,12 +175,34 @@
// Run codegen to generate BUILD files
codegenContext := bp2build.NewCodegenContext(ctx.Config(), ctx, bp2build.ApiBp2build, topDir)
absoluteApiBp2buildDir := shared.JoinPath(topDir, cmdlineArgs.BazelApiBp2buildDir)
- err := createBazelWorkspace(codegenContext, absoluteApiBp2buildDir)
+ // Always generate bp2build_all_srcs filegroups in api_bp2build.
+ // This is necessary to force each Android.bp file to create an equivalent BUILD file
+ // and prevent package boundray issues.
+ // e.g.
+ // Source
+ // f/b/Android.bp
+ // java_library{
+ // name: "foo",
+ // api: "api/current.txt",
+ // }
+ //
+ // f/b/api/Android.bp <- will cause package boundary issues
+ //
+ // Gen
+ // f/b/BUILD
+ // java_contribution{
+ // name: "foo.contribution",
+ // api: "//f/b/api:current.txt",
+ // }
+ //
+ // If we don't generate f/b/api/BUILD, foo.contribution will be unbuildable.
+ err := createBazelWorkspace(codegenContext, absoluteApiBp2buildDir, true)
maybeQuit(err, "")
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 +471,7 @@
"bazel-genfiles",
"bazel-out",
"bazel-testlogs",
+ "bazel-workspace",
"bazel-" + filepath.Base(topDir),
}
}
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
index 45b451c..ce32184 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -25,11 +25,11 @@
)
// A helper function to generate a Read-only Bazel workspace in outDir
-func createBazelWorkspace(ctx *bp2build.CodegenContext, outDir string) error {
+func createBazelWorkspace(ctx *bp2build.CodegenContext, outDir string, generateFilegroups bool) error {
os.RemoveAll(outDir)
ruleShims := bp2build.CreateRuleShims(android.ModuleTypeFactories())
- res, err := bp2build.GenerateBazelTargets(ctx, true)
+ res, err := bp2build.GenerateBazelTargets(ctx, generateFilegroups)
if err != nil {
panic(err)
}
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 661bd5d..3d8458c 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -180,14 +180,15 @@
log.Cleanup()
stat.Finish()
})
-
+ criticalPath := status.NewCriticalPath()
buildCtx := build.Context{ContextImpl: &build.ContextImpl{
- Context: ctx,
- Logger: log,
- Metrics: met,
- Tracer: trace,
- Writer: output,
- Status: stat,
+ Context: ctx,
+ Logger: log,
+ Metrics: met,
+ Tracer: trace,
+ Writer: output,
+ Status: stat,
+ CriticalPath: criticalPath,
}}
config := c.config(buildCtx, args...)
@@ -200,6 +201,7 @@
rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
bp2buildMetricsFile := filepath.Join(logsDir, c.logsPrefix+"bp2build_metrics.pb")
bazelMetricsFile := filepath.Join(logsDir, c.logsPrefix+"bazel_metrics.pb")
+ soongBuildMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_build_metrics.pb")
//the profile file generated by Bazel"
bazelProfileFile := filepath.Join(logsDir, c.logsPrefix+"analyzed_bazel_profile.txt")
@@ -209,6 +211,7 @@
bp2buildMetricsFile, // high level metrics related to bp2build.
soongMetricsFile, // high level metrics related to this build system.
bazelMetricsFile, // high level metrics related to bazel execution
+ soongBuildMetricsFile, // high level metrics related to soong build(except bp2build)
config.BazelMetricsDir(), // directory that contains a set of bazel metrics.
}
@@ -218,12 +221,14 @@
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)
+ // Should run before Metric.Dump
+ defer criticalPath.WriteToMetrics(met)
+
+ c.run(buildCtx, config, args)
}
@@ -252,7 +257,7 @@
stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, logsPrefix+"verbose.log")))
stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, logsPrefix+"error.log")))
stat.AddOutput(status.NewProtoErrorLog(log, buildErrorFile))
- stat.AddOutput(status.NewCriticalPath(log))
+ stat.AddOutput(status.NewCriticalPathLogger(log, buildCtx.CriticalPath))
stat.AddOutput(status.NewBuildProgressLog(log, filepath.Join(logsDir, logsPrefix+"build_progress.pb")))
buildCtx.Verbosef("Detected %.3v GB total RAM", float32(config.TotalRAM())/(1024*1024*1024))
diff --git a/compliance/OWNERS b/compliance/OWNERS
new file mode 100644
index 0000000..f52e201
--- /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/cuj/cuj.go b/cuj/cuj.go
index 869e0f7..de6f10d 100644
--- a/cuj/cuj.go
+++ b/cuj/cuj.go
@@ -94,7 +94,7 @@
stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, "verbose.log")))
stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, "error.log")))
stat.AddOutput(status.NewProtoErrorLog(log, filepath.Join(logsDir, "build_error")))
- stat.AddOutput(status.NewCriticalPath(log))
+ stat.AddOutput(status.NewCriticalPathLogger(log, nil))
defer met.Dump(filepath.Join(logsDir, "soong_metrics"))
diff --git a/dexpreopt/OWNERS b/dexpreopt/OWNERS
deleted file mode 100644
index 5a2a198..0000000
--- 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 e3404a5..a590c72 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -101,6 +101,10 @@
}
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 2d71271..0000000
--- 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/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index b0660df..dcd7fdc 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -717,7 +717,7 @@
}
}
- for propName, productConfigProps := range android.ProductVariableProperties(ctx) {
+ for propName, productConfigProps := range android.ProductVariableProperties(ctx, ctx.Module()) {
for configProp, propVal := range productConfigProps {
if propName == "Src" {
props, ok := propVal.(*string)
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index a6477dd..0d44c31 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -140,6 +140,7 @@
"LOCAL_REQUIRED_MODULES": {"modA", "moduleB"},
"LOCAL_HOST_REQUIRED_MODULES": {"hostModA", "hostModB"},
"LOCAL_TARGET_REQUIRED_MODULES": {"targetModA"},
+ "LOCAL_SOONG_MODULE_TYPE": {"prebuilt_etc"},
}
mod := result.Module("foo", "android_arm64_armv8-a").(*PrebuiltEtc)
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 25b8fe8..023c69a 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -22,6 +22,7 @@
"strings"
"android/soong/android"
+ "android/soong/cc"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -498,3 +499,11 @@
}
return fmt.Sprintf("%x", h.Sum(nil))
}
+
+// Base cc.UseCoverage
+
+var _ cc.UseCoverage = (*filesystem)(nil)
+
+func (*filesystem) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
+ return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled()
+}
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index 444ffd0..aef4756 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -20,6 +20,9 @@
"android/soong/android"
"android/soong/cc"
+ "android/soong/etc"
+
+ "github.com/google/blueprint/proptools"
)
func TestMain(m *testing.M) {
@@ -28,6 +31,7 @@
var fixture = android.GroupFixturePreparers(
android.PrepareForIntegrationTestWithAndroid,
+ etc.PrepareForTestWithPrebuiltEtc,
cc.PrepareForIntegrationTestWithCc,
PrepareForTestWithFilesystemBuildComponents,
)
@@ -188,3 +192,93 @@
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")
+}
+
+func TestFileSystemWithCoverageVariants(t *testing.T) {
+ context := android.GroupFixturePreparers(
+ fixture,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.GcovCoverage = proptools.BoolPtr(true)
+ variables.Native_coverage = proptools.BoolPtr(true)
+ }),
+ )
+
+ result := context.RunTestWithBp(t, `
+ prebuilt_etc {
+ name: "prebuilt",
+ src: ":myfilesystem",
+ }
+
+ 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",
+ stl: "none",
+ }
+ `)
+
+ filesystem := result.ModuleForTests("myfilesystem", "android_common_cov")
+ inputs := filesystem.Output("deps.zip").Implicits
+ android.AssertStringListContains(t, "filesystem should have libfoo(cov)",
+ inputs.Strings(),
+ "out/soong/.intermediates/libfoo/android_arm64_armv8-a_shared_cov/libfoo.so")
+ android.AssertStringListContains(t, "filesystem should have libbar(cov)",
+ inputs.Strings(),
+ "out/soong/.intermediates/libbar/android_arm64_armv8-a_shared_cov/libbar.so")
+
+ filesystemOutput := filesystem.Output("myfilesystem.img").Output
+ prebuiltInput := result.ModuleForTests("prebuilt", "android_arm64_armv8-a").Rule("Cp").Input
+ if filesystemOutput != prebuiltInput {
+ t.Error("prebuilt should use cov variant of filesystem")
+ }
+}
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index 5e5769b..8175a37 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -69,42 +69,222 @@
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))
}
- return true
- } else {
- return false
+
+ 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
}
type FuzzConfig struct {
@@ -112,19 +292,24 @@
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 @@
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 5b71b1e..0000000
--- 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 a483e13..4bc5465 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -219,13 +219,32 @@
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
@@ -1048,10 +1067,7 @@
neverlink := true
ctx.CreateBazelTargetModule(
- bazel.BazelTargetModuleProperties{
- Rule_class: "android_library",
- Bzl_load_location: "//build/bazel/rules/android:rules.bzl",
- },
+ AndroidLibraryBazelTargetModuleProperties(),
android.CommonAttributes{Name: name + "-neverlink"},
&bazelAndroidLibrary{
javaLibraryAttributes: &javaLibraryAttributes{
@@ -1062,6 +1078,12 @@
)
}
+func AndroidLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperties {
+ return bazel.BazelTargetModuleProperties{
+ Rule_class: "android_library",
+ Bzl_load_location: "//build/bazel/rules/android:rules.bzl",
+ }
+}
func (a *AndroidLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
commonAttrs, bp2buildInfo := a.convertLibraryAttrsBp2Build(ctx)
@@ -1073,16 +1095,8 @@
} else if !depLabels.Deps.IsEmpty() {
ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.")
}
-
- if len(a.properties.Common_srcs) != 0 {
- commonAttrs.Common_srcs = bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, a.properties.Common_srcs))
- }
-
name := a.Name()
- props := bazel.BazelTargetModuleProperties{
- Rule_class: "android_library",
- Bzl_load_location: "//build/bazel/rules/android:rules.bzl",
- }
+ props := AndroidLibraryBazelTargetModuleProperties()
ctx.CreateBazelTargetModule(
props,
diff --git a/java/app.go b/java/app.go
index 5234808..8b54bc8 100755
--- a/java/app.go
+++ b/java/app.go
@@ -984,8 +984,11 @@
// 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 @@
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
@@ -1487,6 +1495,10 @@
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
}
+type manifestValueAttribute struct {
+ MinSdkVersion *string
+}
+
type bazelAndroidAppAttributes struct {
*javaCommonAttributes
*bazelAapt
@@ -1494,6 +1506,7 @@
Custom_package *string
Certificate bazel.LabelAttribute
Certificate_name bazel.StringAttribute
+ Manifest_values *manifestValueAttribute
}
// ConvertWithBp2build is used to convert android_app to Bazel.
@@ -1508,11 +1521,23 @@
certificate, certificateName := android.BazelStringOrLabelFromProp(ctx, a.overridableAppProperties.Certificate)
+ manifestValues := &manifestValueAttribute{}
+ // TODO(b/274474008 ): Directly convert deviceProperties.Min_sdk_version in bp2build
+ // MinSdkVersion(ctx) calls SdkVersion(ctx) if no value for min_sdk_version is set
+ minSdkSpec := a.MinSdkVersion(ctx)
+ if !minSdkSpec.ApiLevel.IsPreview() && minSdkSpec.Valid() {
+ minSdkStr, err := minSdkSpec.EffectiveVersionString(ctx)
+ if err == nil {
+ manifestValues.MinSdkVersion = &minSdkStr
+ }
+ }
+
appAttrs := &bazelAndroidAppAttributes{
// TODO(b/209576404): handle package name override by product variable PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES
Custom_package: a.overridableAppProperties.Package_name,
Certificate: certificate,
Certificate_name: certificateName,
+ Manifest_values: manifestValues,
}
props := bazel.BazelTargetModuleProperties{
@@ -1520,18 +1545,14 @@
Bzl_load_location: "//build/bazel/rules/android:rules.bzl",
}
- if !bp2BuildInfo.hasKotlinSrcs && len(a.properties.Common_srcs) == 0 {
+ if !bp2BuildInfo.hasKotlin {
appAttrs.javaCommonAttributes = commonAttrs
appAttrs.bazelAapt = aapt
appAttrs.Deps = deps
} else {
ktName := a.Name() + "_kt"
- commonAttrs.Common_srcs = bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, a.properties.Common_srcs))
ctx.CreateBazelTargetModule(
- bazel.BazelTargetModuleProperties{
- Rule_class: "android_library",
- Bzl_load_location: "//build/bazel/rules/android:rules.bzl",
- },
+ AndroidLibraryBazelTargetModuleProperties(),
android.CommonAttributes{Name: ktName},
&bazelAndroidLibrary{
javaLibraryAttributes: &javaLibraryAttributes{
diff --git a/java/app_import_test.go b/java/app_import_test.go
index a29606f..528fffe 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -363,11 +363,14 @@
a := variant.Module().(*AndroidAppImport)
expectedValues := []string{test.expected}
- actualValues := android.AndroidMkEntriesForTest(t, ctx, a)[0].EntryMap["LOCAL_INSTALLED_MODULE_STEM"]
+ entries := android.AndroidMkEntriesForTest(t, ctx, a)[0]
+ actualValues := entries.EntryMap["LOCAL_INSTALLED_MODULE_STEM"]
if !reflect.DeepEqual(actualValues, expectedValues) {
t.Errorf("Incorrect LOCAL_INSTALLED_MODULE_STEM value '%s', expected '%s'",
actualValues, expectedValues)
}
+ android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "android_app_import", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
+
rule := variant.Rule("genProvenanceMetaData")
android.AssertStringEquals(t, "Invalid input", test.expectedArtifactPath, rule.Inputs[0].String())
android.AssertStringEquals(t, "Invalid output", test.expectedMetaDataPath, rule.Output.String())
@@ -560,6 +563,7 @@
} else if actualSoongResourceExportPackage[0] != expectedSoongResourceExportPackage {
t.Errorf("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE mismatch, actual: %s, expected: %s", actualSoongResourceExportPackage[0], expectedSoongResourceExportPackage)
}
+ android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "android_app_import", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
}
func TestAndroidAppImport_relativeInstallPath(t *testing.T) {
diff --git a/java/app_set.go b/java/app_set.go
index 0f55b77..d2d3b06 100644
--- a/java/app_set.go
+++ b/java/app_set.go
@@ -142,6 +142,7 @@
"allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)),
"screen-densities": screenDensities,
"sdk-version": ctx.Config().PlatformSdkVersion().String(),
+ "skip-sdk-check": strconv.FormatBool(ctx.Config().IsEnvTrue("SOONG_SKIP_APPSET_SDK_CHECK")),
"stem": as.BaseModuleName(),
"apkcerts": as.apkcertsFile.String(),
"partition": as.PartitionTag(ctx.DeviceConfig()),
diff --git a/java/app_set_test.go b/java/app_set_test.go
index 03eb667..10bc5de 100644
--- a/java/app_set_test.go
+++ b/java/app_set_test.go
@@ -89,6 +89,7 @@
"allow-prereleased": "false",
"screen-densities": "LDPI,XXHDPI",
"sdk-version": "29",
+ "skip-sdk-check": "false",
"stem": "foo",
},
},
@@ -105,6 +106,7 @@
"allow-prereleased": "false",
"screen-densities": "all",
"sdk-version": "30",
+ "skip-sdk-check": "false",
"stem": "foo",
},
},
diff --git a/java/app_test.go b/java/app_test.go
index 3fb67c1..5b16cea 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1005,6 +1005,7 @@
platformSdkInt int
platformSdkCodename string
platformSdkFinal bool
+ minSdkVersionBp string
expectedMinSdkVersion string
platformApis bool
activeCodenames []string
@@ -1052,6 +1053,14 @@
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 @@
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 @@
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 @@
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 @@
"--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 cce06a4..7e95abd 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1003,7 +1003,7 @@
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 @@
}
// 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 @@
// 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
}
@@ -1914,15 +1924,15 @@
"stub-annotations", "private-stub-annotations-jar",
"core-lambda-stubs", "core-generated-annotation-stubs":
return javaCore, true
- case "android_stubs_current":
+ case android.SdkPublic.JavaLibraryName(ctx.Config()):
return javaSdk, true
- case "android_system_stubs_current":
+ case android.SdkSystem.JavaLibraryName(ctx.Config()):
return javaSystem, true
- case "android_module_lib_stubs_current":
+ case android.SdkModule.JavaLibraryName(ctx.Config()):
return javaModule, true
- case "android_system_server_stubs_current":
+ case android.SdkSystemServer.JavaLibraryName(ctx.Config()):
return javaSystemServer, true
- case "android_test_stubs_current":
+ case android.SdkTest.JavaLibraryName(ctx.Config()):
return javaSystem, true
}
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 101d3ca..c07a94a 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -440,7 +440,7 @@
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 @@
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 @@
}
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/builder.go b/java/builder.go
index 6f8eec9..4626267 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -131,13 +131,13 @@
blueprint.RuleParams{
Command: `rm -rf "$out" && ` +
`${config.ExtractApksCmd} -o "${out}" -zip "${zip}" -allow-prereleased=${allow-prereleased} ` +
- `-sdk-version=${sdk-version} -abis=${abis} ` +
+ `-sdk-version=${sdk-version} -skip-sdk-check=${skip-sdk-check} -abis=${abis} ` +
`--screen-densities=${screen-densities} --stem=${stem} ` +
`-apkcerts=${apkcerts} -partition=${partition} ` +
`${in}`,
CommandDeps: []string{"${config.ExtractApksCmd}"},
},
- "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem", "apkcerts", "partition", "zip")
+ "abis", "allow-prereleased", "screen-densities", "sdk-version", "skip-sdk-check", "stem", "apkcerts", "partition", "zip")
turbine, turbineRE = pctx.RemoteStaticRules("turbine",
blueprint.RuleParams{
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index 259e977..cf81ddb 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -111,7 +111,7 @@
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 7c22076..13670ee 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -93,9 +93,13 @@
"-JXmx4096M",
"-JXX:+TieredCompilation",
"-JXX:TieredStopAtLevel=1",
+ "-JDcom.android.tools.r8.emitRecordAnnotationsInDex",
+ "-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex",
}, dexerJavaVmFlagsList...))
exportedVars.ExportStringListStaticVariable("R8Flags", append([]string{
"-JXmx2048M",
+ "-JDcom.android.tools.r8.emitRecordAnnotationsInDex",
+ "-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex",
}, dexerJavaVmFlagsList...))
exportedVars.ExportStringListStaticVariable("CommonJdkFlags", []string{
@@ -195,6 +199,7 @@
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 a8dd375..7b6a99a 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -184,7 +184,7 @@
"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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
})
}
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 dc85f9e..97fc3d0 100644
--- a/java/dex_test.go
+++ b/java/dex_test.go
@@ -43,6 +43,7 @@
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 77cbe9c..0ffedf6 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -23,10 +23,24 @@
)
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 @@
}
type dexpreopter struct {
- dexpreoptProperties DexpreoptProperties
+ dexpreoptProperties DexpreoptProperties
+ importDexpreoptProperties ImportDexpreoptProperties
installPath android.InstallPath
uncompressedDex bool
@@ -103,6 +118,14 @@
// - 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 @@
// 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 @@
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 @@
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 @@
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 @@
}
}
+ 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 @@
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 @@
}
return entries
}
+
+func (d *dexpreopter) OutputProfilePathOnHost() android.Path {
+ return d.outputProfilePathOnHost
+}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 3effff6..f4827ea 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -16,6 +16,7 @@
import (
"path/filepath"
+ "sort"
"strings"
"android/soong/android"
@@ -287,6 +288,12 @@
// Path of the preloaded classes file.
preloadedClassesFile string
+
+ // The "--compiler-filter" argument.
+ compilerFilter string
+
+ // The "--single-image" argument.
+ singleImage bool
}
// Target-dependent description of a boot image.
@@ -309,17 +316,17 @@
// 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.
//
@@ -394,6 +401,9 @@
for _, ext := range exts {
ret = append(ret, dir.Join(ctx, name+ext))
}
+ if image.singleImage {
+ break
+ }
}
return ret
}
@@ -443,6 +453,10 @@
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 +518,13 @@
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 +544,8 @@
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 +720,11 @@
}
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 +732,23 @@
// 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 +768,16 @@
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)
+ }
+
+ if image.singleImage {
+ cmd.Flag("--single-image")
+ }
+
// 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 +861,10 @@
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 +1044,8 @@
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 4d0bd09..8c62c33 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -44,6 +44,8 @@
bootImageConfigRawKey = android.NewOnceKey("bootImageConfigRaw")
artBootImageName = "art"
frameworkBootImageName = "boot"
+ mainlineBootImageName = "mainline"
+ bootImageStem = "boot"
)
func genBootImageConfigRaw(ctx android.PathContext) map[string]*bootImageConfig {
@@ -52,35 +54,52 @@
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",
+ singleImage: false,
}
// 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",
+ singleImage: false,
+ }
+
+ mainlineCfg := bootImageConfig{
+ extends: &frameworkCfg,
+ name: mainlineBootImageName,
+ stem: bootImageStem,
+ installDirOnHost: frameworkSubdir,
+ installDirOnDevice: frameworkSubdir,
+ modules: mainlineBcpModules,
+ compilerFilter: "verify",
+ singleImage: true,
}
return map[string]*bootImageConfig{
artBootImageName: &artCfg,
frameworkBootImageName: &frameworkCfg,
+ mainlineBootImageName: &mainlineCfg,
}
}).(map[string]*bootImageConfig)
}
@@ -92,10 +111,7 @@
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 +147,42 @@
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 +191,10 @@
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 b704d09..cd7f295 100644
--- a/java/dexpreopt_config_test.go
+++ b/java/dexpreopt_config_test.go
@@ -28,8 +28,10 @@
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 1c236d8..86dd329 100644
--- a/java/dexpreopt_config_testing.go
+++ b/java/dexpreopt_config_testing.go
@@ -39,6 +39,78 @@
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 @@
imagePathOnHost string
imagePathOnDevice string
imagesDeps []string
- primaryImages string
- primaryImagesDeps []string
+ baseImages []string
+ baseImagesDeps []string
// Mutated fields
installs []normalizedInstall
@@ -413,8 +485,8 @@
"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 @@
"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 @@
"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 @@
"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,290 @@
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",
+ },
+ 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",
+ },
+ },
+ 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",
+ },
+ },
+ 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",
+ },
+ },
+ 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",
+ },
+ 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",
+ },
+ },
+ 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",
+ },
+ },
+ 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",
+ },
+ },
+ 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",
+ },
+ 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",
+ },
+ },
+ 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",
+ },
+ },
+ 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",
+ },
+ },
+ 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",
+ },
+ 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",
+ },
+ },
+ 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",
+ },
+ },
+ 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",
+ },
+ },
+ 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 +1020,8 @@
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 +1068,10 @@
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
+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
+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
+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
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 +1080,10 @@
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
+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
+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
+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
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 +1092,17 @@
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 +1113,10 @@
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
+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
+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
+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
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 +1125,13 @@
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
+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
+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
+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
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 +1140,10 @@
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 01a2c14..e98b9ea 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -603,12 +603,10 @@
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 @@
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 @@
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 @@
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 cf9c7ad..c4fc65f 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -20,10 +20,17 @@
"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 @@
// 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 593d772..e2db0cd 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -236,9 +236,9 @@
testStubModules = append(testStubModules, "sdk_test_current_android")
} else {
// Use stub modules built from source
- publicStubModules = append(publicStubModules, "android_stubs_current")
- systemStubModules = append(systemStubModules, "android_system_stubs_current")
- testStubModules = append(testStubModules, "android_test_stubs_current")
+ publicStubModules = append(publicStubModules, android.SdkPublic.JavaLibraryName(config))
+ systemStubModules = append(systemStubModules, android.SdkSystem.JavaLibraryName(config))
+ testStubModules = append(testStubModules, android.SdkTest.JavaLibraryName(config))
}
// We do not have prebuilts of the core platform api yet
corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs")
@@ -697,7 +697,7 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 659f98a..0841dad 100644
--- a/java/java.go
+++ b/java/java.go
@@ -517,14 +517,8 @@
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 @@
// 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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 @@
module.AddProperties(
&module.properties,
&module.dexer.dexProperties,
+ &module.importDexpreoptProperties,
)
module.initModuleAndImport(module)
@@ -2562,10 +2607,10 @@
type javaCommonAttributes struct {
*javaResourcesAttributes
- Srcs bazel.LabelListAttribute
- Plugins bazel.LabelListAttribute
- Javacopts bazel.StringListAttribute
- Common_srcs bazel.LabelListAttribute
+ *kotlinAttributes
+ Srcs bazel.LabelListAttribute
+ Plugins bazel.LabelListAttribute
+ Javacopts bazel.StringListAttribute
}
type javaDependencyLabels struct {
@@ -2592,8 +2637,8 @@
// depending on the module type.
type bp2BuildJavaInfo struct {
// separates dependencies into dynamic dependencies and static dependencies.
- DepLabels *javaDependencyLabels
- hasKotlinSrcs bool
+ DepLabels *javaDependencyLabels
+ hasKotlin bool
}
// convertLibraryAttrsBp2Build returns a javaCommonAttributes struct with
@@ -2615,6 +2660,7 @@
}
}
}
+ srcs.ResolveExcludes()
javaSrcPartition := "java"
protoSrcPartition := "proto"
@@ -2740,9 +2786,18 @@
depLabels.Deps = deps
depLabels.StaticDeps = bazel.MakeLabelListAttribute(staticDeps)
+ hasKotlin := !kotlinSrcs.IsEmpty()
+ commonAttrs.kotlinAttributes = &kotlinAttributes{
+ Kotlincflags: &m.properties.Kotlincflags,
+ }
+ if len(m.properties.Common_srcs) != 0 {
+ hasKotlin = true
+ commonAttrs.kotlinAttributes.Common_srcs = bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Common_srcs))
+ }
+
bp2BuildInfo := &bp2BuildJavaInfo{
- DepLabels: depLabels,
- hasKotlinSrcs: !kotlinSrcs.IsEmpty(),
+ DepLabels: depLabels,
+ hasKotlin: hasKotlin,
}
return commonAttrs, bp2BuildInfo
@@ -2755,6 +2810,25 @@
Neverlink bazel.BoolAttribute
}
+type kotlinAttributes struct {
+ Common_srcs bazel.LabelListAttribute
+ Kotlincflags *[]string
+}
+
+func ktJvmLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperties {
+ return bazel.BazelTargetModuleProperties{
+ Rule_class: "kt_jvm_library",
+ Bzl_load_location: "//build/bazel/rules/kotlin:rules.bzl",
+ }
+}
+
+func javaLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperties {
+ return bazel.BazelTargetModuleProperties{
+ Rule_class: "java_library",
+ Bzl_load_location: "//build/bazel/rules/java:rules.bzl",
+ }
+}
+
func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) {
commonAttrs, bp2BuildInfo := m.convertLibraryAttrsBp2Build(ctx)
depLabels := bp2BuildInfo.DepLabels
@@ -2767,6 +2841,9 @@
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.")
@@ -2780,18 +2857,10 @@
}
name := m.Name()
- if !bp2BuildInfo.hasKotlinSrcs && len(m.properties.Common_srcs) == 0 {
- props = bazel.BazelTargetModuleProperties{
- Rule_class: "java_library",
- Bzl_load_location: "//build/bazel/rules/java:library.bzl",
- }
+ if !bp2BuildInfo.hasKotlin {
+ props = javaLibraryBazelTargetModuleProperties()
} else {
- attrs.javaCommonAttributes.Common_srcs = bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Common_srcs))
-
- props = bazel.BazelTargetModuleProperties{
- Rule_class: "kt_jvm_library",
- Bzl_load_location: "@rules_kotlin//kotlin:jvm_library.bzl",
- }
+ props = ktJvmLibraryBazelTargetModuleProperties()
}
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, attrs)
@@ -2870,55 +2939,38 @@
}
props := bazel.BazelTargetModuleProperties{
- Rule_class: "java_binary",
+ Rule_class: "java_binary",
+ Bzl_load_location: "//build/bazel/rules/java:rules.bzl",
}
- attrs := &javaBinaryHostAttributes{
+ binAttrs := &javaBinaryHostAttributes{
Runtime_deps: runtimeDeps,
Main_class: mainClass,
Jvm_flags: jvmFlags,
}
- if !bp2BuildInfo.hasKotlinSrcs && len(m.properties.Common_srcs) == 0 {
- attrs.javaCommonAttributes = commonAttrs
- attrs.Deps = deps
- } else {
- ktName := m.Name() + "_kt"
- ktProps := bazel.BazelTargetModuleProperties{
- Rule_class: "kt_jvm_library",
- Bzl_load_location: "@rules_kotlin//kotlin:jvm_library.bzl",
- }
- ktAttrs := &javaLibraryAttributes{
- Deps: deps,
- javaCommonAttributes: &javaCommonAttributes{
- Srcs: commonAttrs.Srcs,
- Plugins: commonAttrs.Plugins,
- Javacopts: commonAttrs.Javacopts,
- },
- }
-
- if len(m.properties.Common_srcs) != 0 {
- ktAttrs.javaCommonAttributes.Common_srcs = bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Common_srcs))
- }
-
- // kt_jvm_library does not support resource_strip_prefix, if this attribute
- // is set, than javaResourcesAttributes needs to be set in the
- // javaCommonAttributes of the java_binary target
- if commonAttrs.javaResourcesAttributes != nil {
- if commonAttrs.javaResourcesAttributes.Resource_strip_prefix != nil {
- attrs.javaCommonAttributes = &javaCommonAttributes{
- javaResourcesAttributes: commonAttrs.javaResourcesAttributes,
- }
- } else {
- ktAttrs.javaCommonAttributes.javaResourcesAttributes = commonAttrs.javaResourcesAttributes
- }
- }
-
- ctx.CreateBazelTargetModule(ktProps, android.CommonAttributes{Name: ktName}, ktAttrs)
- attrs.Runtime_deps.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + ktName}})
+ if commonAttrs.Srcs.IsEmpty() {
+ binAttrs.javaCommonAttributes = commonAttrs
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, binAttrs)
+ return
}
+ libName := m.Name() + "_lib"
+ var libProps bazel.BazelTargetModuleProperties
+ if bp2BuildInfo.hasKotlin {
+ libProps = ktJvmLibraryBazelTargetModuleProperties()
+ } else {
+ libProps = javaLibraryBazelTargetModuleProperties()
+ }
+ libAttrs := &javaLibraryAttributes{
+ Deps: deps,
+ javaCommonAttributes: commonAttrs,
+ }
+
+ ctx.CreateBazelTargetModule(libProps, android.CommonAttributes{Name: libName}, libAttrs)
+ binAttrs.Runtime_deps.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + libName}})
+
// Create the BazelTargetModule.
- ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, binAttrs)
}
type bazelJavaImportAttributes struct {
@@ -2942,7 +2994,10 @@
attrs := &bazelJavaImportAttributes{
Jars: jars,
}
- props := bazel.BazelTargetModuleProperties{Rule_class: "java_import"}
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "java_import",
+ Bzl_load_location: "//build/bazel/rules/java:rules.bzl",
+ }
name := android.RemoveOptionalPrebuiltPrefix(i.Name())
@@ -2953,7 +3008,10 @@
Neverlink: bazel.BoolAttribute{Value: &neverlink},
Exports: bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + name}),
}
- ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{Rule_class: "java_library"}, android.CommonAttributes{Name: name + "-neverlink"}, neverlinkAttrs)
+ ctx.CreateBazelTargetModule(
+ javaLibraryBazelTargetModuleProperties(),
+ android.CommonAttributes{Name: name + "-neverlink"},
+ neverlinkAttrs)
}
diff --git a/java/java_test.go b/java/java_test.go
index 21993ec..68b749b 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -615,6 +615,13 @@
android.AssertPathRelativeToTopEquals(t, "baz dex jar build path", expectedDexJar, bazDexJar)
ctx.ModuleForTests("qux", "android_common").Rule("Cp")
+
+ entries := android.AndroidMkEntriesForTest(t, ctx, fooModule.Module())[0]
+ android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "java_library", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
+ entries = android.AndroidMkEntriesForTest(t, ctx, barModule.Module())[0]
+ android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "java_import", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
+ entries = android.AndroidMkEntriesForTest(t, ctx, ctx.ModuleForTests("sdklib", "android_common").Module())[0]
+ android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "java_sdk_library_import", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
}
func assertDeepEquals(t *testing.T, message string, expected interface{}, actual interface{}) {
@@ -2037,11 +2044,11 @@
}{
{
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 +2120,7 @@
},
{
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 +2135,80 @@
}
}
+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 07b9629..58b43df 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -96,9 +96,10 @@
}
type lintOutputs struct {
- html android.Path
- text android.Path
- xml android.Path
+ html android.Path
+ text android.Path
+ xml android.Path
+ referenceBaseline android.Path
depSets LintDepSets
}
@@ -159,6 +160,50 @@
}
}
+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 +314,25 @@
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,
@@ -400,7 +451,7 @@
html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
- baseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
+ referenceBaseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
@@ -414,26 +465,17 @@
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()
@@ -472,7 +514,7 @@
cmd.FlagWithInput("--baseline ", lintBaseline.Path())
}
- cmd.FlagWithOutput("--write-reference-baseline ", baseline)
+ cmd.FlagWithOutput("--write-reference-baseline ", referenceBaseline)
cmd.Text("; EXITCODE=$?; ")
@@ -494,9 +536,10 @@
rule.Build("lint", "lint")
l.outputs = lintOutputs{
- html: html,
- text: text,
- xml: xml,
+ html: html,
+ text: text,
+ xml: xml,
+ referenceBaseline: referenceBaseline,
depSets: depSetsBuilder.Build(),
}
@@ -528,9 +571,10 @@
}
type lintSingleton struct {
- htmlZip android.WritablePath
- textZip android.WritablePath
- xmlZip android.WritablePath
+ htmlZip android.WritablePath
+ textZip android.WritablePath
+ xmlZip android.WritablePath
+ referenceBaselineZip android.WritablePath
}
func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
@@ -558,54 +602,39 @@
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")
+ 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: copiedLintDatabaseFilesPath(ctx, files.annotationCopiedName),
+ })
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.CpIfChanged,
+ Input: android.OutputFileForModule(ctx, apiVersionsDb, ".api_versions.xml"),
+ Output: copiedLintDatabaseFilesPath(ctx, files.apiVersionsCopiedName),
+ })
}
-
- filteredDb := findModuleOrErr(ctx, "api-versions-xml-public-filtered")
- if filteredDb == nil {
- if !ctx.Config().AllowMissingDependencies() {
- ctx.Errorf("lint: missing api-versions-xml-public-filtered")
- }
- 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"),
- })
}
-func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
- return android.PathForOutput(ctx, "lint", "annotations.zip")
-}
-
-func copiedAPIVersionsXmlPath(ctx android.PathContext, name string) android.WritablePath {
+func copiedLintDatabaseFilesPath(ctx android.PathContext, name string) android.WritablePath {
return android.PathForOutput(ctx, "lint", name)
}
@@ -658,12 +687,15 @@
l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
- ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
+ l.referenceBaselineZip = android.PathForOutput(ctx, "lint-report-reference-baselines.zip")
+ zip(l.referenceBaselineZip, func(l *lintOutputs) android.Path { return l.referenceBaseline })
+
+ ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip)
}
func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
if !ctx.Config().UnbundledBuild() {
- ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
+ ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip)
}
}
diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt
index 061f4d0..1bb4996 100644
--- a/java/lint_defaults.txt
+++ b/java/lint_defaults.txt
@@ -40,6 +40,13 @@
# NewApi checks will continue to be enforced for apex deps since
# lint.strict_updatability_linting will be true for those Soong modules
--disable_check NewApi
+# Disable ChromeOS specific checks
+--disable_check PermissionImpliesUnsupportedChromeOsHardware
+# Disable UnsafeImplicitIntentLaunch until it can avoid false positives/crash
+# TODO(265425607)
+--disable_check UnsafeImplicitIntentLaunch
+# InvalidId will give errors on ids defined like android:id="@androidprv:id/contentPanel"
+--disable_check InvalidId
# Downgrade existing errors to warnings
--warning_check AppCompatResource # 55 occurences in 10 modules
diff --git a/java/lint_test.go b/java/lint_test.go
index 62450d5..ec901aa 100644
--- a/java/lint_test.go
+++ b/java/lint_test.go
@@ -113,8 +113,9 @@
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 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 @@
}
`
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 @@
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 f0de7a4..0ea3609 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -129,7 +129,7 @@
// 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) 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) 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 @@
// 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 @@
// 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 c6acd55..206d995 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -264,7 +264,7 @@
}
// 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 @@
}
}
// 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 68f27b8..008b8b1 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -302,6 +302,9 @@
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 b0da5af..72a5006 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -57,14 +57,10 @@
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() <= 33 {
return JAVA_VERSION_11
+ } else {
+ return JAVA_VERSION_17
}
}
@@ -195,12 +191,8 @@
bootclasspath: corePlatformBootclasspathLibraries(ctx),
noFrameworksLibs: true,
}
- case android.SdkPublic:
- return toModule("android_stubs_current", sdkFrameworkAidlPath(ctx))
- case android.SdkSystem:
- return toModule("android_system_stubs_current", sdkFrameworkAidlPath(ctx))
- case android.SdkTest:
- return toModule("android_test_stubs_current", sdkFrameworkAidlPath(ctx))
+ case android.SdkPublic, android.SdkSystem, android.SdkTest:
+ return toModule(sdkVersion.Kind.JavaLibraryName(ctx.Config()), sdkFrameworkAidlPath(ctx))
case android.SdkCore:
return sdkDep{
useModule: true,
@@ -210,10 +202,10 @@
}
case android.SdkModule:
// TODO(146757305): provide .apk and .aidl that have more APIs for modules
- return toModule("android_module_lib_stubs_current", nonUpdatableFrameworkAidlPath(ctx))
+ return toModule(sdkVersion.Kind.JavaLibraryName(ctx.Config()), nonUpdatableFrameworkAidlPath(ctx))
case android.SdkSystemServer:
// TODO(146757305): provide .apk and .aidl that have more APIs for modules
- return toModule("android_system_server_stubs_current", sdkFrameworkAidlPath(ctx))
+ return toModule(sdkVersion.Kind.JavaLibraryName(ctx.Config()), sdkFrameworkAidlPath(ctx))
default:
panic(fmt.Errorf("invalid sdk %q", sdkVersion.Raw))
}
@@ -276,9 +268,9 @@
// Create framework.aidl by extracting anything that implements android.os.Parcelable from the SDK stubs modules.
func createSdkFrameworkAidl(ctx android.SingletonContext) {
stubsModules := []string{
- "android_stubs_current",
- "android_test_stubs_current",
- "android_system_stubs_current",
+ android.SdkPublic.JavaLibraryName(ctx.Config()),
+ android.SdkTest.JavaLibraryName(ctx.Config()),
+ android.SdkSystem.JavaLibraryName(ctx.Config()),
}
combinedAidl := sdkFrameworkAidlPath(ctx)
@@ -293,7 +285,7 @@
// Creates a version of framework.aidl for the non-updatable part of the platform.
func createNonUpdatableFrameworkAidl(ctx android.SingletonContext) {
- stubsModules := []string{"android_module_lib_stubs_current"}
+ stubsModules := []string{android.SdkModule.JavaLibraryName(ctx.Config())}
combinedAidl := nonUpdatableFrameworkAidlPath(ctx)
tempPath := tempPathForRestat(ctx, combinedAidl)
@@ -388,10 +380,7 @@
} else if ctx.Config().FrameworksBaseDirExists(ctx) && !ctx.Config().AlwaysUsePrebuiltSdks() {
cmd.Text("cat")
apiTxtFileModules := []string{
- "frameworks-base-api-current.txt",
- "frameworks-base-api-system-current.txt",
- "frameworks-base-api-module-lib-current.txt",
- "frameworks-base-api-system-server-current.txt",
+ "api_fingerprint",
}
count := 0
ctx.VisitAllModules(func(module android.Module) {
@@ -402,10 +391,10 @@
}
})
if count != len(apiTxtFileModules) {
- ctx.Errorf("Could not find all the expected API modules %v, found %d\n", apiTxtFileModules, count)
+ ctx.Errorf("Could not find expected API module %v, found %d\n", apiTxtFileModules, count)
return
}
- cmd.Text("| md5sum | cut -d' ' -f1 >").
+ cmd.Text(">").
Output(out)
} else {
// Unbundled build
diff --git a/java/sdk_library.go b/java/sdk_library.go
index b872365..d2fbfd9 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -28,6 +28,7 @@
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/bazel"
"android/soong/dexpreopt"
)
@@ -546,14 +547,14 @@
// 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 SdkLibrary struct {
Library
+ android.BazelModuleBase
+
sdkLibraryProperties sdkLibraryProperties
// Map from api scope to the scope specific property structure.
@@ -1376,7 +1379,7 @@
})
// 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 @@
}
}
- mctx.CreateModule(DroidstubsFactory, &props)
+ mctx.CreateModule(DroidstubsFactory, &props).(*Droidstubs).CallHookIfAvailable(mctx)
}
func (module *SdkLibrary) compareAgainstLatestApi(apiScope *apiScope) bool {
@@ -2081,9 +2084,48 @@
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 @@
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 @@
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 @@
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 @@
//
// 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 @@
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 @@
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 210bfc3..1d0c13d 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -120,6 +120,7 @@
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 e6f76e1..63d7dba 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -198,7 +198,7 @@
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 fddfc48..0000000
--- 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 31f0460..0000000
--- a/linkerconfig/proto/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-kiyoungkim@google.com
-jiyong@google.com
-jooyung@google.com
diff --git a/mk2rbc/Android.bp b/mk2rbc/Android.bp
index 4fa3eb6..cd80a4d 100644
--- a/mk2rbc/Android.bp
+++ b/mk2rbc/Android.bp
@@ -19,7 +19,7 @@
blueprint_go_binary {
name: "mk2rbc",
- srcs: ["cmd/mk2rbc.go"],
+ srcs: ["mk2rbc/mk2rbc.go"],
deps: [
"mk2rbc-lib",
"androidmk-parser",
diff --git a/mk2rbc/cmd/mk2rbc.go b/mk2rbc/mk2rbc/mk2rbc.go
similarity index 100%
rename from mk2rbc/cmd/mk2rbc.go
rename to mk2rbc/mk2rbc/mk2rbc.go
diff --git a/multitree/api_imports.go b/multitree/api_imports.go
index 6674d3e..07ec7bc 100644
--- a/multitree/api_imports.go
+++ b/multitree/api_imports.go
@@ -40,8 +40,9 @@
}
type apiImportsProperties struct {
- Shared_libs []string // List of C shared libraries from API surfaces
- Header_libs []string // List of C header libraries from API surfaces
+ Shared_libs []string // List of C shared libraries from API surfaces
+ Header_libs []string // List of C header libraries from API surfaces
+ Apex_shared_libs []string // List of C shared libraries with APEX stubs
}
// 'api_imports' is a module which describes modules available from API surfaces.
@@ -60,7 +61,7 @@
}
type ApiImportInfo struct {
- SharedLibs, HeaderLibs map[string]string
+ SharedLibs, HeaderLibs, ApexSharedLibs map[string]string
}
var ApiImportsProvider = blueprint.NewMutatorProvider(ApiImportInfo{}, "deps")
@@ -78,10 +79,12 @@
sharedLibs := generateNameMapWithSuffix(imports.properties.Shared_libs)
headerLibs := generateNameMapWithSuffix(imports.properties.Header_libs)
+ apexSharedLibs := generateNameMapWithSuffix(imports.properties.Apex_shared_libs)
ctx.SetProvider(ApiImportsProvider, ApiImportInfo{
- SharedLibs: sharedLibs,
- HeaderLibs: headerLibs,
+ SharedLibs: sharedLibs,
+ HeaderLibs: headerLibs,
+ ApexSharedLibs: apexSharedLibs,
})
}
diff --git a/python/python.go b/python/python.go
index 18e5b68..c7c523d 100644
--- a/python/python.go
+++ b/python/python.go
@@ -263,6 +263,12 @@
versionProps = append(versionProps, props.Version.Py3)
}
if proptools.BoolDefault(props.Version.Py2.Enabled, false) {
+ if !mctx.DeviceConfig().BuildBrokenUsesSoongPython2Modules() &&
+ mctx.ModuleName() != "par_test" &&
+ mctx.ModuleName() != "py2-cmd" &&
+ mctx.ModuleName() != "py2-stdlib" {
+ mctx.PropertyErrorf("version.py2.enabled", "Python 2 is no longer supported, please convert to python 3. This error can be temporarily overridden by setting BUILD_BROKEN_USES_SOONG_PYTHON2_MODULES := true in the product configuration")
+ }
versionNames = append(versionNames, pyVersion2)
versionProps = append(versionProps, props.Version.Py2)
}
@@ -532,7 +538,7 @@
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/python/test.go b/python/test.go
index fb8e918..31da17e 100644
--- a/python/test.go
+++ b/python/test.go
@@ -15,6 +15,8 @@
package python
import (
+ "fmt"
+
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -63,7 +65,22 @@
Java_data []string
// Test options.
- Test_options android.CommonTestOptions
+ Test_options TestOptions
+}
+
+type TestOptions struct {
+ android.CommonTestOptions
+
+ // Runner for the test. Supports "tradefed" and "mobly" (for multi-device tests). Default is "tradefed".
+ Runner *string
+
+ // Metadata to describe the test configuration.
+ Metadata []Metadata
+}
+
+type Metadata struct {
+ Name string
+ Value string
}
type PythonTestModule struct {
@@ -94,14 +111,41 @@
p.PythonLibraryModule.GenerateAndroidBuildActions(ctx)
p.buildBinary(ctx)
- p.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
- TestConfigProp: p.testProperties.Test_config,
- TestConfigTemplateProp: p.testProperties.Test_config_template,
- TestSuites: p.binaryProperties.Test_suites,
- AutoGenConfig: p.binaryProperties.Auto_gen_config,
- DeviceTemplate: "${PythonBinaryHostTestConfigTemplate}",
- HostTemplate: "${PythonBinaryHostTestConfigTemplate}",
- })
+ var configs []tradefed.Option
+ for _, metadata := range p.testProperties.Test_options.Metadata {
+ configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: metadata.Name, Value: metadata.Value})
+ }
+
+ runner := proptools.StringDefault(p.testProperties.Test_options.Runner, "tradefed")
+ if runner == "tradefed" {
+ p.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
+ TestConfigProp: p.testProperties.Test_config,
+ TestConfigTemplateProp: p.testProperties.Test_config_template,
+ TestSuites: p.binaryProperties.Test_suites,
+ OptionsForAutogenerated: configs,
+ AutoGenConfig: p.binaryProperties.Auto_gen_config,
+ DeviceTemplate: "${PythonBinaryHostTestConfigTemplate}",
+ HostTemplate: "${PythonBinaryHostTestConfigTemplate}",
+ })
+ } else if runner == "mobly" {
+ if p.testProperties.Test_config != nil || p.testProperties.Test_config_template != nil || p.binaryProperties.Auto_gen_config != nil {
+ panic(fmt.Errorf("cannot set test_config, test_config_template or auto_gen_config for mobly test"))
+ }
+
+ for _, testSuite := range p.binaryProperties.Test_suites {
+ if testSuite == "cts" {
+ configs = append(configs, tradefed.Option{Name: "test-suite-tag", Value: "cts"})
+ break
+ }
+ }
+ p.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
+ OptionsForAutogenerated: configs,
+ DeviceTemplate: "${PythonBinaryHostMoblyTestConfigTemplate}",
+ HostTemplate: "${PythonBinaryHostMoblyTestConfigTemplate}",
+ })
+ } else {
+ panic(fmt.Errorf("unknown python test runner '%s', should be 'tradefed' or 'mobly'", runner))
+ }
p.installedDest = ctx.InstallFile(installDir(ctx, "nativetest", "nativetest64", ctx.ModuleName()), p.installSource.Base(), p.installSource)
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 32c746e..5e680b0 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -43,6 +43,10 @@
}
}
+func (mod *Module) AndroidMkSuffix() string {
+ return mod.Properties.RustSubName + mod.Properties.SubName
+}
+
func (mod *Module) AndroidMkEntries() []android.AndroidMkEntries {
if mod.Properties.HideFromMake || mod.hideApexVariantFromMake {
@@ -79,8 +83,7 @@
mod.SubAndroidMk(&ret, mod.sanitize)
}
- ret.SubName += mod.Properties.RustSubName
- ret.SubName += mod.Properties.SubName
+ ret.SubName += mod.AndroidMkSuffix()
return []android.AndroidMkEntries{ret}
}
@@ -152,6 +155,11 @@
})
}
+func (library *snapshotLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
+ ctx.SubAndroidMk(ret, library.libraryDecorator)
+ ret.SubName = library.SnapshotAndroidMkSuffix()
+}
+
func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
ctx.SubAndroidMk(ret, procMacro.baseCompiler)
@@ -205,8 +213,8 @@
})
}
-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 +237,14 @@
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 e81ec6b..8cec918 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -52,7 +52,7 @@
if ctx.Config().UseHostMusl() {
return "musl/lib/"
} else {
- return "lib64/"
+ return "lib/"
}
})
_ = pctx.SourcePathVariable("bindgenClang",
@@ -313,7 +313,7 @@
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 7dd9dd2..4b20e2b 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -134,6 +134,8 @@
func TransformSrctoDylib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath) buildOutput {
+ flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
+
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib")
}
@@ -247,7 +249,13 @@
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\"")
}
// Collect linker flags
@@ -399,7 +407,7 @@
// 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 8ec42f0..06ae12f 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -208,6 +208,10 @@
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) 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/arm64_device.go b/rust/config/arm64_device.go
index 186e571..ae783e8 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -30,6 +30,7 @@
"armv8-a-branchprot": []string{},
"armv8-2a": []string{},
"armv8-2a-dotprod": []string{},
+ "armv9-a": []string{},
}
)
diff --git a/rust/config/global.go b/rust/config/global.go
index 50ac1f7..8894938 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
var pctx = android.NewPackageContext("android/soong/rust/config")
var (
- RustDefaultVersion = "1.65.0.p1"
+ RustDefaultVersion = "1.68.0"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2021"
Stdlibs = []string{
@@ -54,6 +54,7 @@
// TODO (b/267698452): Temporary workaround until the "no unstable
// features" policy is enforced.
"-A stable-features",
+ "-Zdylib-lto",
}
deviceGlobalRustFlags = []string{
diff --git a/rust/config/x86_linux_bionic_host.go b/rust/config/x86_linux_bionic_host.go
index b1a2c17..79c40ce 100644
--- a/rust/config/x86_linux_bionic_host.go
+++ b/rust/config/x86_linux_bionic_host.go
@@ -21,7 +21,9 @@
)
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 5ea481f..bc6504d 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -21,6 +21,7 @@
)
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 @@
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 @@
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 6faf55c..d7e7ddf 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -16,8 +16,6 @@
import (
"path/filepath"
- "sort"
- "strings"
"android/soong/android"
"android/soong/cc"
@@ -27,14 +25,14 @@
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 @@
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) 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 @@
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 @@
"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 8185872..fb4d9c1 100644
--- a/rust/image_test.go
+++ b/rust/image_test.go
@@ -53,6 +53,7 @@
crate_name: "foo",
srcs: ["foo.rs"],
vendor_available: true,
+ product_available: true,
}
`)
@@ -61,6 +62,35 @@
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 28a300b..018cdab 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -26,6 +26,7 @@
"android/soong/cc"
cc_config "android/soong/cc/config"
"android/soong/fuzz"
+ "android/soong/multitree"
"android/soong/rust/config"
"android/soong/snapshot"
)
@@ -62,11 +63,11 @@
}
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 +209,11 @@
}
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 +491,7 @@
SetDisabled()
stdLinkage(ctx *depsContext) RustLinkage
+ noStdlibs() bool
unstrippedOutputFilePath() android.Path
strippedOutputFilePath() android.OptionalPath
@@ -619,6 +626,31 @@
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()
@@ -1080,6 +1112,17 @@
return nil
}
+func rustMakeLibName(ctx android.ModuleContext, c cc.LinkableInterface, dep cc.LinkableInterface, depName string) string {
+ if rustDep, ok := dep.(*Module); ok {
+ // Use base module name for snapshots when exporting to Makefile.
+ if snapshotPrebuilt, ok := rustDep.compiler.(cc.SnapshotInterface); ok {
+ baseName := rustDep.BaseModuleName()
+ return baseName + snapshotPrebuilt.SnapshotAndroidMkSuffix() + rustDep.AndroidMkSuffix()
+ }
+ }
+ return cc.MakeLibName(ctx, c, dep, depName)
+}
+
func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
var depPaths PathDeps
@@ -1105,13 +1148,59 @@
mod.apexSdkVersion = android.FutureApiLevel
}
+ skipModuleList := map[string]bool{}
+
+ var apiImportInfo multitree.ApiImportInfo
+ hasApiImportInfo := false
+
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ if dep.Name() == "api_imports" {
+ apiImportInfo = ctx.OtherModuleProvider(dep, multitree.ApiImportsProvider).(multitree.ApiImportInfo)
+ hasApiImportInfo = true
+ }
+ })
+
+ if hasApiImportInfo {
+ targetStubModuleList := map[string]string{}
+ targetOrigModuleList := map[string]string{}
+
+ // Search for dependency which both original module and API imported library with APEX stub exists
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ depName := ctx.OtherModuleName(dep)
+ if apiLibrary, ok := apiImportInfo.ApexSharedLibs[depName]; ok {
+ targetStubModuleList[apiLibrary] = depName
+ }
+ })
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ depName := ctx.OtherModuleName(dep)
+ if origLibrary, ok := targetStubModuleList[depName]; ok {
+ targetOrigModuleList[origLibrary] = depName
+ }
+ })
+
+ // Decide which library should be used between original and API imported library
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ depName := ctx.OtherModuleName(dep)
+ if apiLibrary, ok := targetOrigModuleList[depName]; ok {
+ if cc.ShouldUseStubForApex(ctx, dep) {
+ skipModuleList[depName] = true
+ } else {
+ skipModuleList[apiLibrary] = true
+ }
+ }
+ })
+ }
+
ctx.VisitDirectDeps(func(dep android.Module) {
depName := ctx.OtherModuleName(dep)
depTag := ctx.OtherModuleDependencyTag(dep)
+ if _, exists := skipModuleList[depName]; exists {
+ return
+ }
if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() {
//Handle Rust Modules
- makeLibName := cc.MakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName)
+ makeLibName := rustMakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName)
switch depTag {
case dylibDepTag:
@@ -1364,6 +1453,16 @@
return strings.Split(filepath.String(), filepath.Base())[0]
}
+// usePublicApi returns true if the rust variant should link against NDK (publicapi)
+func (r *Module) usePublicApi() bool {
+ return r.Device() && r.UseSdk()
+}
+
+// useVendorApi returns true if the rust variant should link against LLNDK (vendorapi)
+func (r *Module) useVendorApi() bool {
+ return r.Device() && (r.InVendor() || r.InProduct())
+}
+
func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
ctx := &depsContext{
BottomUpMutatorContext: actx,
@@ -1374,8 +1473,10 @@
var snapshotInfo *cc.SnapshotInfo
apiImportInfo := cc.GetApiImports(mod, actx)
- for idx, lib := range deps.SharedLibs {
- deps.SharedLibs[idx] = cc.GetReplaceModuleName(lib, apiImportInfo.SharedLibs)
+ if mod.usePublicApi() || mod.useVendorApi() {
+ for idx, lib := range deps.SharedLibs {
+ deps.SharedLibs[idx] = cc.GetReplaceModuleName(lib, apiImportInfo.SharedLibs)
+ }
}
if ctx.Os() == android.Android {
@@ -1455,7 +1556,15 @@
variations := []blueprint.Variation{
{Mutator: "link", Variation: "shared"},
}
- cc.AddSharedLibDependenciesWithVersions(ctx, mod, variations, depTag, name, version, false)
+ // For core variant, add a dep on the implementation (if it exists) and its .apiimport (if it exists)
+ // GenerateAndroidBuildActions will pick the correct impl/stub based on the api_domain boundary
+ if _, ok := apiImportInfo.ApexSharedLibs[name]; !ok || ctx.OtherModuleExists(name) {
+ cc.AddSharedLibDependenciesWithVersions(ctx, mod, variations, depTag, name, version, false)
+ }
+
+ if apiLibraryName, ok := apiImportInfo.ApexSharedLibs[name]; ok {
+ cc.AddSharedLibDependenciesWithVersions(ctx, mod, variations, depTag, apiLibraryName, version, false)
+ }
}
for _, lib := range deps.WholeStaticLibs {
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
index 7be0042..e1b3c86 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -424,6 +424,14 @@
compile_multilib: "32",
srcs: ["bin.rs"],
}
+
+ rust_library {
+ name: "librust_vendor_available",
+ crate_name: "rust_vendor",
+ vendor_available: true,
+ srcs: ["client.rs"],
+ }
+
`
vndkBp := `
@@ -499,13 +507,6 @@
system_shared_libs: [],
}
- rust_library {
- name: "librust_vendor_available",
- crate_name: "rust_vendor",
- vendor_available: true,
- srcs: ["client.rs"],
- }
-
rust_ffi_shared {
name: "libclient",
crate_name: "client",
@@ -963,7 +964,7 @@
}
libclientAndroidMkRlibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkRlibs
- if g, w := libclientAndroidMkRlibs, []string{"librust_vendor_available.vendor_rlib.30.arm64.rlib-std", "libstd.vendor_rlib.30.arm64"}; !reflect.DeepEqual(g, w) {
+ if g, w := libclientAndroidMkRlibs, []string{"librust_vendor_available.vendor.rlib-std", "libstd.vendor"}; !reflect.DeepEqual(g, w) {
t.Errorf("wanted libclient libclientAndroidMkRlibs %q, got %q", w, g)
}
@@ -978,10 +979,24 @@
}
libclientRustAndroidMkRlibs := ctx.ModuleForTests("libclient_rust", rlibVariant).Module().(*Module).Properties.AndroidMkRlibs
- if g, w := libclientRustAndroidMkRlibs, []string{"librust_vendor_available.vendor_rlib.30.arm64.rlib-std", "libstd.vendor_rlib.30.arm64"}; !reflect.DeepEqual(g, w) {
+ if g, w := libclientRustAndroidMkRlibs, []string{"librust_vendor_available.vendor.rlib-std", "libstd.vendor"}; !reflect.DeepEqual(g, w) {
t.Errorf("wanted libclient libclientAndroidMkRlibs %q, got %q", w, g)
}
+ // rust vendor snapshot must have ".vendor" suffix in AndroidMk
+ librustVendorAvailableSnapshotModule := ctx.ModuleForTests("librust_vendor_available.vendor_rlib.30.arm64", rlibVariant).Module()
+ librustVendorSnapshotMkName := android.AndroidMkEntriesForTest(t, ctx, librustVendorAvailableSnapshotModule)[0].EntryMap["LOCAL_MODULE"][0]
+ expectedRustVendorSnapshotName := "librust_vendor_available.vendor.rlib-std"
+ if librustVendorSnapshotMkName != expectedRustVendorSnapshotName {
+ t.Errorf("Unexpected rust vendor snapshot name in AndroidMk: %q, expected: %q\n", librustVendorSnapshotMkName, expectedRustVendorSnapshotName)
+ }
+
+ rustVendorBinModule := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Module()
+ rustVendorBinMkRlibName := android.AndroidMkEntriesForTest(t, ctx, rustVendorBinModule)[0].EntryMap["LOCAL_RLIB_LIBRARIES"][0]
+ if rustVendorBinMkRlibName != expectedRustVendorSnapshotName {
+ t.Errorf("Unexpected rust rlib name in AndroidMk: %q, expected: %q\n", rustVendorBinMkRlibName, expectedRustVendorSnapshotName)
+ }
+
binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustc").Args["linkFlags"]
libVndkStaticOutputPaths := cc.GetOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.30.arm64"})
if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) {
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 5dd45cd..26fe432 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -191,6 +191,17 @@
],
}
+python_test_host {
+ name: "conv_linker_config_test",
+ main: "conv_linker_config_test.py",
+ srcs: [
+ "conv_linker_config_test.py",
+ "conv_linker_config.py",
+ ],
+ libs: ["linker_config_proto"],
+ test_suites: ["general-tests"],
+}
+
python_binary_host {
name: "get_clang_version",
main: "get_clang_version.py",
@@ -220,3 +231,8 @@
srcs: ["rustfmt.toml"],
visibility: ["//visibility:public"],
}
+
+sh_binary_host {
+ name: "jars-to-module-info-java",
+ src: "jars-to-module-info-java.sh",
+}
diff --git a/scripts/OWNERS b/scripts/OWNERS
deleted file mode 100644
index 7b003fd..0000000
--- 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/build-ndk-prebuilts.sh b/scripts/build-ndk-prebuilts.sh
index b57963b..0d14019 100755
--- a/scripts/build-ndk-prebuilts.sh
+++ b/scripts/build-ndk-prebuilts.sh
@@ -19,7 +19,12 @@
exit 1
fi
-TARGET_PRODUCT=ndk build/soong/soong_ui.bash --make-mode --soong-only ${OUT_DIR}/soong/ndk.timestamp
+# TODO: remove ALLOW_MISSING_DEPENDENCIES=true when all the riscv64
+# dependencies exist (currently blocked by http://b/273792258).
+# TODO: remove BUILD_BROKEN_DISABLE_BAZEL=1 when bazel supports riscv64 (http://b/262192655).
+ALLOW_MISSING_DEPENDENCIES=true \
+BUILD_BROKEN_DISABLE_BAZEL=1 \
+ TARGET_PRODUCT=ndk build/soong/soong_ui.bash --make-mode --soong-only ${OUT_DIR}/soong/ndk.timestamp
if [ -n "${DIST_DIR}" ]; then
mkdir -p ${DIST_DIR} || true
diff --git a/scripts/check_boot_jars/package_allowed_list.txt b/scripts/check_boot_jars/package_allowed_list.txt
index 08bd80c..869fd3f 100644
--- a/scripts/check_boot_jars/package_allowed_list.txt
+++ b/scripts/check_boot_jars/package_allowed_list.txt
@@ -8,9 +8,11 @@
java\.io
java\.lang
java\.lang\.annotation
+java\.lang\.constant
java\.lang\.invoke
java\.lang\.ref
java\.lang\.reflect
+java\.lang\.runtime
java\.math
java\.net
java\.nio
diff --git a/scripts/conv_linker_config.py b/scripts/conv_linker_config.py
index 3d7c0fa..3ac1b7e 100644
--- a/scripts/conv_linker_config.py
+++ b/scripts/conv_linker_config.py
@@ -19,6 +19,7 @@
import collections
import json
import os
+import sys
import linker_config_pb2 #pylint: disable=import-error
from google.protobuf.descriptor import FieldDescriptor
@@ -26,16 +27,41 @@
from google.protobuf.text_format import MessageToString
+def LoadJsonMessage(path):
+ """
+ Loads a message from a .json file with `//` comments strippedfor convenience.
+ """
+ json_content = ''
+ with open(path) as f:
+ for line in f:
+ if not line.lstrip().startswith('//'):
+ json_content += line
+ obj = json.loads(json_content, object_pairs_hook=collections.OrderedDict)
+ return ParseDict(obj, linker_config_pb2.LinkerConfig())
+
+
def Proto(args):
+ """
+ Merges input json files (--source) into a protobuf message (--output).
+ Fails if the output file exists. Set --force or --append to deal with the existing
+ output file.
+ --force to overwrite the output file with the input (.json files).
+ --append to append the input to the output file.
+ """
pb = linker_config_pb2.LinkerConfig()
- for input in args.source.split(':'):
- json_content = ''
- with open(input) as f:
- for line in f:
- if not line.lstrip().startswith('//'):
- json_content += line
- obj = json.loads(json_content, object_pairs_hook=collections.OrderedDict)
- ParseDict(obj, pb)
+ if os.path.isfile(args.output):
+ if args.force:
+ pass
+ elif args.append:
+ with open(args.output, 'rb') as f:
+ pb.ParseFromString(f.read())
+ else:
+ sys.stderr.write(f'Error: {args.output} exists. Use --force or --append.\n')
+ sys.exit(1)
+
+ if args.source:
+ for input in args.source.split(':'):
+ pb.MergeFrom(LoadJsonMessage(input))
with open(args.output, 'wb') as f:
f.write(pb.SerializeToString())
@@ -104,7 +130,7 @@
parser_proto.add_argument(
'-s',
'--source',
- required=True,
+ nargs='?',
type=str,
help='Colon-separated list of linker configuration files in JSON.')
parser_proto.add_argument(
@@ -113,6 +139,17 @@
required=True,
type=str,
help='Target path to create protobuf file.')
+ option_for_existing_output = parser_proto.add_mutually_exclusive_group()
+ option_for_existing_output.add_argument(
+ '-f',
+ '--force',
+ action='store_true',
+ help='Overwrite if the output file exists.')
+ option_for_existing_output.add_argument(
+ '-a',
+ '--append',
+ action='store_true',
+ help='Append the input to the output file if the output file exists.')
parser_proto.set_defaults(func=Proto)
print_proto = subparsers.add_parser(
@@ -194,8 +231,12 @@
def main():
- args = GetArgParser().parse_args()
- args.func(args)
+ parser = GetArgParser()
+ args = parser.parse_args()
+ if 'func' in args:
+ args.func(args)
+ else:
+ parser.print_help()
if __name__ == '__main__':
diff --git a/scripts/conv_linker_config_test.py b/scripts/conv_linker_config_test.py
new file mode 100644
index 0000000..d19a47b
--- /dev/null
+++ b/scripts/conv_linker_config_test.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+"""Unit tests for conv_linker_config.py."""
+
+import io
+import os
+import shutil
+import tempfile
+import unittest
+
+import conv_linker_config
+from contextlib import redirect_stderr
+from linker_config_pb2 import LinkerConfig
+
+class FileArgs:
+ def __init__(self, files, sep = ':'):
+ self.files = files
+ self.sep = sep
+
+
+class FileArg:
+ def __init__(self, file):
+ self.file = file
+
+
+class TempDirTest(unittest.TestCase):
+
+ def setUp(self):
+ self.tempdir = tempfile.mkdtemp()
+
+
+ def tearDown(self):
+ shutil.rmtree(self.tempdir)
+
+
+ def write(self, name, contents):
+ with open(os.path.join(self.tempdir, name), 'wb') as f:
+ f.write(contents)
+
+
+ def read(self, name):
+ with open(os.path.join(self.tempdir, name), 'rb') as f:
+ return f.read()
+
+
+ def resolve_paths(self, args):
+ for i in range(len(args)):
+ if isinstance(args[i], FileArgs):
+ args[i] = args[i].sep.join(os.path.join(self.tempdir, f.file) for f in args[i].files)
+ elif isinstance(args[i], FileArg):
+ args[i] = os.path.join(self.tempdir, args[i].file)
+ return args
+
+
+class ConvLinkerConfigTest(TempDirTest):
+ """Unit tests for conv_linker_config."""
+
+
+ def test_Proto_empty_input(self):
+ self.command(['proto', '-s', '-o', FileArg('out.pb')])
+ pb = LinkerConfig()
+ pb.ParseFromString(self.read('out.pb'))
+ self.assertEqual(pb, LinkerConfig())
+
+
+ def test_Proto_single_input(self):
+ self.write('foo.json', b'{ "provideLibs": ["libfoo.so"]}')
+ self.command(['proto', '-s', FileArg('foo.json'), '-o', FileArg('out.pb')])
+ pb = LinkerConfig()
+ pb.ParseFromString(self.read('out.pb'))
+ self.assertSequenceEqual(pb.provideLibs, ['libfoo.so'])
+
+
+ def test_Proto_with_multiple_input(self):
+ self.write('foo.json', b'{ "provideLibs": ["libfoo.so"]}')
+ self.write('bar.json', b'{ "provideLibs": ["libbar.so"]}')
+ self.command(['proto', '-s', FileArgs([FileArg('foo.json'), FileArg('bar.json')]), '-o', FileArg('out.pb')])
+ pb = LinkerConfig()
+ pb.ParseFromString(self.read('out.pb'))
+ self.assertSetEqual(set(pb.provideLibs), set(['libfoo.so', 'libbar.so']))
+
+
+ def test_Proto_with_existing_output(self):
+ self.write('out.pb', LinkerConfig(provideLibs=['libfoo.so']).SerializeToString())
+ buf = io.StringIO()
+ with self.assertRaises(SystemExit) as err:
+ with redirect_stderr(buf):
+ self.command(['proto', '-o', FileArg('out.pb')])
+ self.assertEqual(err.exception.code, 1)
+ self.assertRegex(buf.getvalue(), r'.*out\.pb exists')
+
+
+ def test_Proto_with_append(self):
+ self.write('out.pb', LinkerConfig(provideLibs=['libfoo.so']).SerializeToString())
+ self.write('bar.json', b'{ "provideLibs": ["libbar.so"]}')
+ self.command(['proto', '-s', FileArg('bar.json'), '-o', FileArg('out.pb'), '-a'])
+ pb = LinkerConfig()
+ pb.ParseFromString(self.read('out.pb'))
+ self.assertSetEqual(set(pb.provideLibs), set(['libfoo.so', 'libbar.so']))
+
+
+ def test_Proto_with_force(self):
+ self.write('out.pb', LinkerConfig(provideLibs=['libfoo.so']).SerializeToString())
+ self.write('bar.json', b'{ "provideLibs": ["libbar.so"]}')
+ self.command(['proto', '-s', FileArg('bar.json'), '-o', FileArg('out.pb'), '-f'])
+ pb = LinkerConfig()
+ pb.ParseFromString(self.read('out.pb'))
+ self.assertSetEqual(set(pb.provideLibs), set(['libbar.so']))
+
+
+ def command(self, args):
+ parser = conv_linker_config.GetArgParser()
+ parsed_args = parser.parse_args(self.resolve_paths(args))
+ parsed_args.func(parsed_args)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/scripts/test_config_fixer.py b/scripts/test_config_fixer.py
index 3dbc22e..07e01a1 100644
--- a/scripts/test_config_fixer.py
+++ b/scripts/test_config_fixer.py
@@ -31,6 +31,8 @@
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 @@
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 @@
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 @@
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 39ce5b3..699f91e 100644
--- a/scripts/test_config_fixer_test.py
+++ b/scripts/test_config_fixer_test.py
@@ -23,6 +23,8 @@
import test_config_fixer
+from manifest import write_xml
+
sys.dont_write_bytecode = True
@@ -117,5 +119,39 @@
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 d81635e..0d6496d 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -27,6 +27,11 @@
// 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 @@
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 @@
}),
// 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 @@
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 @@
// 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
@@ -819,6 +839,7 @@
compile_dex: true,
public: {enabled: true},
permitted_packages: ["mysdklibrary"],
+ min_sdk_version: "current",
}
java_sdk_library {
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 2ade146..3a2ecc0 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -33,7 +33,8 @@
// 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 2a17cdc..66c44c8 100644
--- a/sdk/systemserverclasspath_fragment_sdk_test.go
+++ b/sdk/systemserverclasspath_fragment_sdk_test.go
@@ -62,6 +62,9 @@
min_sdk_version: "2",
compile_dex: true,
permitted_packages: ["mylib"],
+ dex_preopt: {
+ profile: "art-profile",
+ },
}
java_sdk_library {
@@ -71,6 +74,9 @@
shared_library: false,
public: {enabled: true},
min_sdk_version: "2",
+ dex_preopt: {
+ profile: "art-profile",
+ },
}
`),
).RunTest(t)
@@ -105,6 +111,9 @@
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 @@
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 @@
`)
})
+ 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 f50439c..d98ab68 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -357,6 +357,12 @@
// If the minApiLevel of the member is greater than the target API level then exclude it from
// this snapshot.
exclude := memberVariantDep.minApiLevel.GreaterThan(targetApiLevel)
+ // Always include host variants (e.g. host tools) in the snapshot.
+ // Host variants should not be guarded by a min_sdk_version check. In fact, host variants
+ // do not have a `min_sdk_version`.
+ if memberVariantDep.Host() {
+ exclude = false
+ }
addMember(name, export, exclude)
@@ -565,7 +571,7 @@
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 +632,7 @@
getModuleInfo(memberVariantDep.variant)
}
- for _, memberName := range android.SortedStringKeys(name2Info) {
+ for _, memberName := range android.SortedKeys(name2Info) {
info := name2Info[memberName]
modules = append(modules, info)
}
@@ -1263,6 +1269,11 @@
minApiLevel android.ApiLevel
}
+// Host returns true if the sdk member is a host variant (e.g. host tool)
+func (s *sdkMemberVariantDep) Host() bool {
+ return s.variant.Target().Os.Class == android.Host
+}
+
var _ android.SdkMember = (*sdkMember)(nil)
// sdkMember groups all the variants of a specific member module together along with the name of the
@@ -1708,7 +1719,7 @@
}
// 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/soong_ui.bash b/soong_ui.bash
index 7bddb58..8e7cd19 100755
--- a/soong_ui.bash
+++ b/soong_ui.bash
@@ -14,9 +14,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# To track how long we took to startup. %N isn't supported on Darwin, but
-# that's detected in the Go code, which skips calculating the startup time.
-export TRACE_BEGIN_SOONG=$(date +%s%N)
+# To track how long we took to startup.
+case $(uname -s) in
+ Darwin)
+ export TRACE_BEGIN_SOONG=`$T/prebuilts/build-tools/path/darwin-x86/date +%s%3N`
+ ;;
+ *)
+ export TRACE_BEGIN_SOONG=$(date +%s%N)
+ ;;
+esac
source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../make/shell_utils.sh
require_top
@@ -27,8 +33,8 @@
source ${TOP}/build/soong/scripts/microfactory.bash
soong_build_go soong_ui android/soong/cmd/soong_ui
-soong_build_go mk2rbc android/soong/mk2rbc/cmd
-soong_build_go rbcrun rbcrun/cmd
+soong_build_go mk2rbc android/soong/mk2rbc/mk2rbc
+soong_build_go rbcrun rbcrun/rbcrun
cd ${TOP}
exec "$(getoutdir)/soong_ui" "$@"
diff --git a/starlark_fmt/format.go b/starlark_fmt/format.go
index 3e51fa1..064fc21 100644
--- a/starlark_fmt/format.go
+++ b/starlark_fmt/format.go
@@ -17,6 +17,7 @@
import (
"fmt"
"sort"
+ "strconv"
"strings"
)
@@ -84,6 +85,16 @@
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 f3bad73..fda5ca0 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -803,7 +803,6 @@
setup
mkdir -p "a/${GENERATED_BUILD_FILE_NAME}"
- touch a/a.txt
cat > a/Android.bp <<EOF
filegroup {
name: "a",
@@ -813,7 +812,6 @@
EOF
mkdir -p "b/${GENERATED_BUILD_FILE_NAME}"
- touch b/b.txt
cat > b/Android.bp <<EOF
filegroup {
name: "b",
@@ -826,8 +824,8 @@
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 6477dac..68d7f8d 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -21,6 +21,68 @@
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 @@
# 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 @@
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
@@ -238,4 +343,29 @@
run_bazel build --config=android --config=api_bp2build //:empty
}
+# Verify that an *_api_contribution target can refer to an api file from
+# another Bazel package.
+function test_api_export_from_another_bazel_package() {
+ setup
+ # Parent dir Android.bp
+ mkdir -p foo
+ cat > foo/Android.bp << 'EOF'
+cc_library {
+ name: "libfoo",
+ stubs: {
+ symbol_file: "api/libfoo.map.txt",
+ },
+}
+EOF
+ # Child dir Android.bp
+ mkdir -p foo/api
+ cat > foo/api/Android.bp << 'EOF'
+package{}
+EOF
+ touch foo/api/libfoo.map.txt
+ # Run test
+ run_soong api_bp2build
+ run_bazel build --config=android --config=api_bp2build //foo:libfoo.contribution
+}
+
scan_and_run_tests
diff --git a/tests/dcla_apex_comparison_test.sh b/tests/dcla_apex_comparison_test.sh
new file mode 100755
index 0000000..97ae97e
--- /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}" ] && { [ "${lib}" != "libcrypto.so" ] || [ "${module}" != "com.android.tethering" ]; }; 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 0000000..4e2982a
--- /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 eb76a46..e1aa70c 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -7,6 +7,7 @@
"$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,10 @@
# mock client.
"$TOP/build/soong/tests/apex_comparison_tests.sh"
"$TOP/build/soong/tests/apex_comparison_tests.sh" "module_arm64only"
-
+extra_build_params=--bazel-mode-staging "$TOP/build/soong/tests/dcla_apex_comparison_test.sh"
+BUILD_BROKEN_DISABLE_BAZEL=true "$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"
+
+"$TOP/build/soong/tests/sbom_test.sh"
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
new file mode 100755
index 0000000..6066d70
--- /dev/null
+++ b/tests/sbom_test.sh
@@ -0,0 +1,210 @@
+#!/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 -uo pipefail
+
+# Integration test for verifying generated SBOM for cuttlefish device.
+
+if [ ! -e "build/make/core/Makefile" ]; then
+ echo "$0 must be run from the top of the Android source tree."
+ exit 1
+fi
+
+tmp_dir="$(mktemp -d tmp.XXXXXX)"
+function cleanup {
+ rm -rf "${tmp_dir}"
+}
+trap cleanup EXIT
+
+out_dir=$tmp_dir
+droid_target=droid
+
+debug=false
+if [ $debug = "true" ]; then
+ out_dir=out
+ droid_target=
+fi
+# m droid, build sbom later in case additional dependencies might be built and included in partition images.
+TARGET_PRODUCT="aosp_cf_x86_64_phone" TARGET_BUILD_VARIANT=userdebug OUT_DIR=$out_dir \
+ build/soong/soong_ui.bash --make-mode $droid_target dump.erofs
+
+product_out=$out_dir/target/product/vsoc_x86_64
+sbom_test=$product_out/sbom_test
+mkdir $sbom_test
+cp $product_out/*.img $sbom_test
+
+# m sbom
+TARGET_PRODUCT="aosp_cf_x86_64_phone" TARGET_BUILD_VARIANT=userdebug OUT_DIR=$out_dir \
+ build/soong/soong_ui.bash --make-mode sbom
+
+# Generate installed file list from .img files in PRODUCT_OUT
+dump_erofs=$out_dir/host/linux-x86/bin/dump.erofs
+
+declare -A diff_excludes
+diff_excludes[odm]="-I /odm/lib/modules"
+diff_excludes[vendor]=\
+"-I /vendor/lib64/libkeystore2_crypto.so \
+ -I /vendor/lib/modules \
+ -I /vendor/odm"
+diff_excludes[system]=\
+"-I /acct/ \
+ -I /adb_keys \
+ -I /apex/ \
+ -I /bin \
+ -I /bugreports \
+ -I /cache \
+ -I /config/ \
+ -I /d \
+ -I /data/ \
+ -I /data_mirror/ \
+ -I /debug_ramdisk/ \
+ -I /dev/ \
+ -I /etc \
+ -I /init \
+ -I /init.environ.rc \
+ -I /linkerconfig/ \
+ -I /metadata/ \
+ -I /mnt/ \
+ -I /odm/app \
+ -I /odm/bin \
+ -I /odm_dlkm/etc \
+ -I /odm/etc \
+ -I /odm/firmware \
+ -I /odm/framework \
+ -I /odm/lib \
+ -I /odm/lib64 \
+ -I /odm/overlay \
+ -I /odm/priv-app \
+ -I /odm/usr \
+ -I /oem/ \
+ -I /postinstall/ \
+ -I /proc/ \
+ -I /product/ \
+ -I /sdcard \
+ -I /second_stage_resources/ \
+ -I /storage/ \
+ -I /sys/ \
+ -I /system_dlkm/ \
+ -I /system_ext/ \
+ -I /system/lib64/android.hardware.confirmationui@1.0.so \
+ -I /system/lib64/android.hardware.confirmationui-V1-ndk.so \
+ -I /system/lib64/android.hardware.keymaster@4.1.so \
+ -I /system/lib64/android.hardware.security.rkp-V3-ndk.so \
+ -I /system/lib64/android.hardware.security.sharedsecret-V1-ndk.so \
+ -I /system/lib64/android.security.compat-ndk.so \
+ -I /system/lib64/libkeymaster4_1support.so \
+ -I /system/lib64/libkeymint.so \
+ -I /system/lib64/libkeystore2_aaid.so \
+ -I /system/lib64/libkeystore2_apc_compat.so \
+ -I /system/lib64/libkeystore2_crypto.so \
+ -I /system/lib64/libkm_compat_service.so \
+ -I /system/lib64/libkm_compat.so \
+ -I /system/lib64/vndk-29 \
+ -I /system/lib64/vndk-sp-29 \
+ -I /system/lib/modules \
+ -I /system/lib/vndk-29 \
+ -I /system/lib/vndk-sp-29 \
+ -I /system/product \
+ -I /system/system_ext \
+ -I /system/usr/icu \
+ -I /system/vendor \
+ -I /vendor/ \
+ -I /vendor_dlkm/etc"
+
+# Example output of dump.erofs is as below, and the data used in the test start
+# at line 11. Column 1 is inode id, column 2 is inode type and column 3 is name.
+# Each line is captured in variable "entry", sed is used to trim the leading
+# spaces and cut is used to get field 1 every time. Once a field is extracted,
+# "cut --complement" is used to remove the extracted field so next field can be
+# processed in the same way and to be processed field is always field 1.
+# Output of dump.erofs:
+# File : /
+# Size: 160 On-disk size: 160 directory
+# NID: 39 Links: 10 Layout: 2 Compression ratio: 100.00%
+# Inode size: 64 Extent size: 0 Xattr size: 16
+# Uid: 0 Gid: 0 Access: 0755/rwxr-xr-x
+# Timestamp: 2023-02-14 01:15:54.000000000
+#
+# NID TYPE FILENAME
+# 39 2 .
+# 39 2 ..
+# 47 2 app
+# 1286748 2 bin
+# 1286754 2 etc
+# 5304814 2 lib
+# 5309056 2 lib64
+# 5309130 2 media
+# 5388910 2 overlay
+# 5479537 2 priv-app
+EROFS_IMAGES="\
+ $sbom_test/product.img \
+ $sbom_test/system.img \
+ $sbom_test/system_ext.img \
+ $sbom_test/system_dlkm.img \
+ $sbom_test/system_other.img \
+ $sbom_test/odm.img \
+ $sbom_test/odm_dlkm.img \
+ $sbom_test/vendor.img \
+ $sbom_test/vendor_dlkm.img"
+for f in $EROFS_IMAGES; do
+ partition_name=$(basename $f | cut -d. -f1)
+ file_list_file="${sbom_test}/sbom-${partition_name}-files.txt"
+ files_in_spdx_file="${sbom_test}/sbom-${partition_name}-files-in-spdx.txt"
+ rm "$file_list_file" > /dev/null 2>&1
+ all_dirs="/"
+ while [ ! -z "$all_dirs" ]; do
+ dir=$(echo "$all_dirs" | cut -d ' ' -f1)
+ all_dirs=$(echo "$all_dirs" | cut -d ' ' -f1 --complement -s)
+ entries=$($dump_erofs --ls --path "$dir" $f | tail -n +11)
+ while read -r entry; do
+ nid=$(echo $entry | sed 's/^\s*//' | cut -d ' ' -f1)
+ entry=$(echo $entry | sed 's/^\s*//' | cut -d ' ' -f1 --complement)
+ type=$(echo $entry | sed 's/^\s*//' | cut -d ' ' -f1)
+ entry=$(echo $entry | sed 's/^\s*//' | cut -d ' ' -f1 --complement)
+ name=$(echo $entry | sed 's/^\s*//' | cut -d ' ' -f1)
+ case $type in
+ "2") # directory
+ all_dirs=$(echo "$all_dirs $dir/$name" | sed 's/^\s*//')
+ ;;
+ *)
+ (
+ if [ "$partition_name" != "system" ]; then
+ # system partition is mounted to /, not to prepend partition name.
+ printf %s "/$partition_name"
+ fi
+ echo "$dir/$name" | sed 's#^//#/#'
+ ) >> "$file_list_file"
+ ;;
+ esac
+ done <<< "$entries"
+ done
+ sort -n -o "$file_list_file" "$file_list_file"
+
+ # Diff
+ echo ============ Diffing files in $f and SBOM
+ grep "FileName: /${partition_name}/" $product_out/sbom.spdx | sed 's/^FileName: //' | sort -n > "$files_in_spdx_file"
+ exclude=
+ if [ -v 'diff_excludes[$partition_name]' ]; then
+ exclude=${diff_excludes[$partition_name]}
+ fi
+ diff "$file_list_file" "$files_in_spdx_file" $exclude
+ if [ $? != "0" ]; then
+ echo Found diffs in $f and SBOM.
+ exit 1
+ else
+ echo No diffs.
+ fi
+done
\ No newline at end of file
diff --git a/third_party/zip/writer.go b/third_party/zip/writer.go
index f526838..8a957e1 100644
--- a/third_party/zip/writer.go
+++ b/third_party/zip/writer.go
@@ -162,9 +162,17 @@
if records > uint16max {
records = uint16max
}
+ // Only store uint32max for the size and the offset if they don't fit.
+ // Robolectric currently doesn't support zip64 and fails to find the
+ // offset to the central directory when the number of files in the zip
+ // is larger than 2^16.
+ if size > uint32max {
+ size = uint32max
+ }
+ if offset > uint32max {
+ offset = uint32max
+ }
// END ANDROID CHANGE
- size = uint32max
- offset = uint32max
}
// write end record
diff --git a/tradefed/config.go b/tradefed/config.go
index 999424c..326a006 100644
--- a/tradefed/config.go
+++ b/tradefed/config.go
@@ -31,6 +31,7 @@
pctx.SourcePathVariable("NativeBenchmarkTestConfigTemplate", "build/make/core/native_benchmark_test_config_template.xml")
pctx.SourcePathVariable("NativeHostTestConfigTemplate", "build/make/core/native_host_test_config_template.xml")
pctx.SourcePathVariable("NativeTestConfigTemplate", "build/make/core/native_test_config_template.xml")
+ pctx.SourcePathVariable("PythonBinaryHostMoblyTestConfigTemplate", "build/make/core/python_binary_host_mobly_test_config_template.xml")
pctx.SourcePathVariable("PythonBinaryHostTestConfigTemplate", "build/make/core/python_binary_host_test_config_template.xml")
pctx.SourcePathVariable("RustDeviceTestConfigTemplate", "build/make/core/rust_device_test_config_template.xml")
pctx.SourcePathVariable("RustHostTestConfigTemplate", "build/make/core/rust_host_test_config_template.xml")
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index 7a8fca9..b79754c 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -50,6 +50,7 @@
"cleanbuild.go",
"config.go",
"context.go",
+ "staging_snapshot.go",
"dumpvars.go",
"environment.go",
"exec.go",
@@ -70,10 +71,11 @@
"cleanbuild_test.go",
"config_test.go",
"environment_test.go",
+ "proc_sync_test.go",
"rbe_test.go",
+ "staging_snapshot_test.go",
"upload_test.go",
"util_test.go",
- "proc_sync_test.go",
],
darwin: {
srcs: [
diff --git a/ui/build/build.go b/ui/build/build.go
index d49a754..edc595d 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -102,9 +102,9 @@
// Whether to include the kati-generated ninja file in the combined ninja.
RunKatiNinja = 1 << iota
// Whether to run ninja on the combined ninja.
- RunNinja = 1 << iota
- RunBuildTests = 1 << iota
- RunAll = RunProductConfig | RunSoong | RunKati | RunKatiNinja | RunNinja
+ RunNinja = 1 << iota
+ RunDistActions = 1 << iota
+ RunBuildTests = 1 << iota
)
// checkBazelMode fails the build if there are conflicting arguments for which bazel
@@ -322,34 +322,42 @@
runNinjaForBuild(ctx, config)
}
+
+ if what&RunDistActions != 0 {
+ runDistActions(ctx, config)
+ }
}
func evaluateWhatToRun(config Config, verboseln func(v ...interface{})) int {
//evaluate what to run
- what := RunAll
+ what := 0
if config.Checkbuild() {
what |= RunBuildTests
}
- if config.SkipConfig() {
+ if !config.SkipConfig() {
+ what |= RunProductConfig
+ } else {
verboseln("Skipping Config as requested")
- what = what &^ RunProductConfig
}
- if config.SkipKati() {
- verboseln("Skipping Kati as requested")
- what = what &^ RunKati
- }
- if config.SkipKatiNinja() {
- verboseln("Skipping use of Kati ninja as requested")
- what = what &^ RunKatiNinja
- }
- if config.SkipSoong() {
+ if !config.SkipSoong() {
+ what |= RunSoong
+ } else {
verboseln("Skipping use of Soong as requested")
- what = what &^ RunSoong
}
-
- if config.SkipNinja() {
+ if !config.SkipKati() {
+ what |= RunKati
+ } else {
+ verboseln("Skipping Kati as requested")
+ }
+ if !config.SkipKatiNinja() {
+ what |= RunKatiNinja
+ } else {
+ verboseln("Skipping use of Kati ninja as requested")
+ }
+ if !config.SkipNinja() {
+ what |= RunNinja
+ } else {
verboseln("Skipping Ninja as requested")
- what = what &^ RunNinja
}
if !config.SoongBuildInvocationNeeded() {
@@ -361,6 +369,11 @@
what = what &^ RunNinja
what = what &^ RunKati
}
+
+ if config.Dist() {
+ what |= RunDistActions
+ }
+
return what
}
@@ -419,3 +432,9 @@
}
}()
}
+
+// Actions to run on every build where 'dist' is in the actions.
+// Be careful, anything added here slows down EVERY CI build
+func runDistActions(ctx Context, config Config) {
+ runStagingSnapshot(ctx, config)
+}
diff --git a/ui/build/config.go b/ui/build/config.go
index cb7fe1e..20cc9fb 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -45,7 +45,8 @@
)
var (
- rbeRandPrefix int
+ rbeRandPrefix int
+ googleProdCredsExistCache bool
)
func init() {
@@ -77,6 +78,7 @@
queryview bool
reportMkMetrics bool // Collect and report mk2bp migration progress metrics.
soongDocs bool
+ multitreeBuild bool // This is a multitree build.
skipConfig bool
skipKati bool
skipKatiNinja bool
@@ -116,8 +118,21 @@
bazelForceEnabledModules string
includeTags []string
+
+ // Data source to write ninja weight list
+ ninjaWeightListSource NinjaWeightListSource
}
+type NinjaWeightListSource uint
+
+const (
+ // ninja doesn't use weight list.
+ NOT_USED NinjaWeightListSource = iota
+ // ninja uses weight list based on previous builds by ninja log
+ NINJA_LOG
+ // ninja thinks every task has the same weight.
+ EVENLY_DISTRIBUTED
+)
const srcDirFileCheck = "build/soong/root.bp"
var buildFiles = []string{"Android.mk", "Android.bp"}
@@ -369,6 +384,7 @@
"CDPATH",
"DISPLAY",
"GREP_OPTIONS",
+ "JAVAC",
"NDK_ROOT",
"POSIXLY_CORRECT",
@@ -473,6 +489,10 @@
ret.environ.Set("ANDROID_JAVA11_HOME", java11Home)
ret.environ.Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
+ if ret.MultitreeBuild() {
+ ret.environ.Set("MULTITREE_BUILD", "true")
+ }
+
outDir := ret.OutDir()
buildDateTimeFile := filepath.Join(outDir, "build_date.txt")
if buildDateTime, ok := ret.environ.Get("BUILD_DATETIME"); ok && buildDateTime != "" {
@@ -521,6 +541,17 @@
ctx.Metrics.SystemResourceInfo(s)
}
+func getNinjaWeightListSourceInMetric(s NinjaWeightListSource) *smpb.BuildConfig_NinjaWeightListSource {
+ switch s {
+ case NINJA_LOG:
+ return smpb.BuildConfig_NINJA_LOG.Enum()
+ case EVENLY_DISTRIBUTED:
+ return smpb.BuildConfig_EVENLY_DISTRIBUTED.Enum()
+ default:
+ return smpb.BuildConfig_NOT_USED.Enum()
+ }
+}
+
func buildConfig(config Config) *smpb.BuildConfig {
c := &smpb.BuildConfig{
ForceUseGoma: proto.Bool(config.ForceUseGoma()),
@@ -528,6 +559,7 @@
UseRbe: proto.Bool(config.UseRBE()),
BazelMixedBuild: proto.Bool(config.BazelBuildEnabled()),
ForceDisableBazelMixedBuild: proto.Bool(config.IsBazelMixedBuildForceDisabled()),
+ NinjaWeightListSource: getNinjaWeightListSourceInMetric(config.NinjaWeightListSource()),
}
c.Targets = append(c.Targets, config.arguments...)
@@ -780,6 +812,8 @@
c.skipMetricsUpload = true
} else if arg == "--mk-metrics" {
c.reportMkMetrics = true
+ } else if arg == "--multitree-build" {
+ c.multitreeBuild = true
} else if arg == "--bazel-mode" {
c.bazelProdMode = true
} else if arg == "--bazel-mode-dev" {
@@ -788,6 +822,17 @@
c.bazelStagingMode = true
} else if arg == "--search-api-dir" {
c.searchApiDir = true
+ } else if strings.HasPrefix(arg, "--ninja_weight_source=") {
+ source := strings.TrimPrefix(arg, "--ninja_weight_source=")
+ if source == "ninja_log" {
+ c.ninjaWeightListSource = NINJA_LOG
+ } else if source == "evenly_distributed" {
+ c.ninjaWeightListSource = EVENLY_DISTRIBUTED
+ } else if source == "not_used" {
+ c.ninjaWeightListSource = NOT_USED
+ } else {
+ ctx.Fatalf("unknown option for ninja_weight_source: %s", source)
+ }
} else if strings.HasPrefix(arg, "--build-command=") {
buildCmd := strings.TrimPrefix(arg, "--build-command=")
// remove quotations
@@ -1078,6 +1123,14 @@
return c.verbose
}
+func (c *configImpl) MultitreeBuild() bool {
+ return c.multitreeBuild
+}
+
+func (c *configImpl) NinjaWeightListSource() NinjaWeightListSource {
+ return c.ninjaWeightListSource
+}
+
func (c *configImpl) SkipKati() bool {
return c.skipKati
}
@@ -1346,9 +1399,13 @@
// GoogleProdCredsExist determine whether credentials exist on the
// Googler machine to use remote execution.
func (c *configImpl) GoogleProdCredsExist() bool {
+ if googleProdCredsExistCache {
+ return googleProdCredsExistCache
+ }
if _, err := exec.Command("/usr/bin/prodcertstatus", "--simple_output", "--nocheck_loas").Output(); err != nil {
return false
}
+ googleProdCredsExistCache = true
return true
}
@@ -1567,6 +1624,10 @@
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/config_test.go b/ui/build/config_test.go
index 940d85c..a1eccf0 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -903,6 +903,15 @@
tidyOnly: "",
expectedArgs: []string{},
}, {
+ description: "multitree build action executed at root directory",
+ dirsInTrees: []string{},
+ buildFiles: []string{},
+ rootSymlink: false,
+ args: []string{"--multitree-build"},
+ curDir: ".",
+ tidyOnly: "",
+ expectedArgs: []string{"--multitree-build"},
+ }, {
description: "build action executed at root directory in symlink",
dirsInTrees: []string{},
buildFiles: []string{},
@@ -1023,6 +1032,7 @@
UseRbe: proto.Bool(false),
BazelMixedBuild: proto.Bool(false),
ForceDisableBazelMixedBuild: proto.Bool(false),
+ NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
},
},
{
@@ -1034,6 +1044,7 @@
UseRbe: proto.Bool(false),
BazelMixedBuild: proto.Bool(false),
ForceDisableBazelMixedBuild: proto.Bool(false),
+ NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
},
},
{
@@ -1045,6 +1056,7 @@
UseRbe: proto.Bool(false),
BazelMixedBuild: proto.Bool(false),
ForceDisableBazelMixedBuild: proto.Bool(false),
+ NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
},
},
{
@@ -1056,6 +1068,7 @@
UseRbe: proto.Bool(true),
BazelMixedBuild: proto.Bool(false),
ForceDisableBazelMixedBuild: proto.Bool(false),
+ NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
},
},
{
@@ -1067,6 +1080,7 @@
UseRbe: proto.Bool(false),
BazelMixedBuild: proto.Bool(false),
ForceDisableBazelMixedBuild: proto.Bool(true),
+ NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
},
},
{
@@ -1079,6 +1093,7 @@
UseRbe: proto.Bool(false),
BazelMixedBuild: proto.Bool(false),
ForceDisableBazelMixedBuild: proto.Bool(false),
+ NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
},
},
{
@@ -1091,6 +1106,7 @@
UseRbe: proto.Bool(false),
BazelMixedBuild: proto.Bool(true),
ForceDisableBazelMixedBuild: proto.Bool(false),
+ NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
},
},
{
@@ -1103,6 +1119,7 @@
UseRbe: proto.Bool(false),
BazelMixedBuild: proto.Bool(true),
ForceDisableBazelMixedBuild: proto.Bool(false),
+ NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
},
},
{
@@ -1115,6 +1132,7 @@
UseRbe: proto.Bool(false),
BazelMixedBuild: proto.Bool(true),
ForceDisableBazelMixedBuild: proto.Bool(false),
+ NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
},
},
{
@@ -1129,6 +1147,7 @@
BazelMixedBuild: proto.Bool(false),
Targets: []string{"droid", "dist"},
ForceDisableBazelMixedBuild: proto.Bool(false),
+ NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
},
},
{
@@ -1147,6 +1166,7 @@
UseRbe: proto.Bool(true),
BazelMixedBuild: proto.Bool(true),
ForceDisableBazelMixedBuild: proto.Bool(true),
+ NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
},
},
}
diff --git a/ui/build/context.go b/ui/build/context.go
index 2fef0d0..fd20e26 100644
--- a/ui/build/context.go
+++ b/ui/build/context.go
@@ -40,6 +40,8 @@
Thread tracer.Thread
Tracer tracer.Tracer
+
+ CriticalPath *status.CriticalPath
}
// BeginTrace starts a new Duration Event.
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 1e3e547..a9c298f 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -84,6 +84,14 @@
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 @@
}
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 dab1a9b..4734494 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -23,10 +23,59 @@
"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"
+ ninjaLogFileName = ".ninja_log"
+)
+
+func useNinjaBuildLog(ctx Context, config Config, cmd *Cmd) {
+ ninjaLogFile := filepath.Join(config.OutDir(), ninjaLogFileName)
+ data, err := os.ReadFile(ninjaLogFile)
+ var outputBuilder strings.Builder
+ if err == nil {
+ lines := strings.Split(strings.TrimSpace(string(data)), "\n")
+ // ninja log: <start> <end> <restat> <name> <cmdhash>
+ // ninja weight list: <name>,<end-start+1>
+ for _, line := range lines {
+ if strings.HasPrefix(line, "#") {
+ continue
+ }
+ fields := strings.Split(line, "\t")
+ path := fields[3]
+ start, err := strconv.Atoi(fields[0])
+ if err != nil {
+ continue
+ }
+ end, err := strconv.Atoi(fields[1])
+ if err != nil {
+ continue
+ }
+ outputBuilder.WriteString(path)
+ outputBuilder.WriteString(",")
+ outputBuilder.WriteString(strconv.Itoa(end-start+1) + "\n")
+ }
+ } else {
+ // If there is no ninja log file, just pass empty ninja weight list.
+ // Because it is still efficient with critical path calculation logic even without weight.
+ ctx.Verbosef("There is an error during reading ninja log, so ninja will use empty weight list: %s", err)
+ }
+
+ weightListFile := filepath.Join(config.OutDir(), ".ninja_weight_list")
+
+ err = os.WriteFile(weightListFile, []byte(outputBuilder.String()), 0644)
+ if err == nil {
+ cmd.Args = append(cmd.Args, "-o", "usesweightlist="+weightListFile)
+ } else {
+ ctx.Panicf("Could not write ninja weight list file %s", err)
+ }
+}
+
// 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.
@@ -79,6 +128,14 @@
cmd.Environment.AppendFromKati(config.KatiEnvFile())
}
+ switch config.NinjaWeightListSource() {
+ case NINJA_LOG:
+ useNinjaBuildLog(ctx, config, cmd)
+ case EVENLY_DISTRIBUTED:
+ // pass empty weight list means ninja considers every tasks's weight as 1(default value).
+ cmd.Args = append(cmd.Args, "-o", "usesweightlist=/dev/null")
+ }
+
// Allow both NINJA_ARGS and NINJA_EXTRA_ARGS, since both have been
// used in the past to specify extra ninja arguments.
if extra, ok := cmd.Environment.Get("NINJA_ARGS"); ok {
@@ -186,6 +243,21 @@
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.
@@ -194,7 +266,7 @@
ticker := time.NewTicker(ninjaHeartbeatDuration)
defer ticker.Stop()
ninjaChecker := &ninjaStucknessChecker{
- logPath: filepath.Join(config.OutDir(), ".ninja_log"),
+ logPath: filepath.Join(config.OutDir(), ninjaLogFileName),
}
go func() {
for {
diff --git a/ui/build/path.go b/ui/build/path.go
index 86e61c0..29128d8 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -109,6 +109,15 @@
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 @@
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 3c844c1..1d17216 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -100,6 +100,8 @@
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 @@
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 e6543ec..871e637 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -21,6 +21,7 @@
"strconv"
"strings"
+ "android/soong/bazel"
"android/soong/ui/metrics"
"android/soong/ui/status"
@@ -167,6 +168,10 @@
commonArgs = append(commonArgs, "-t")
}
+ if pb.config.multitreeBuild {
+ commonArgs = append(commonArgs, "--multitree-build")
+ }
+
commonArgs = append(commonArgs, "-l", filepath.Join(pb.config.FileListDir(), "Android.bp.list"))
invocationEnv := make(map[string]string)
if pb.debugPort != "" {
@@ -268,9 +273,15 @@
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)
}
+ if config.MultitreeBuild() {
+ mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--multitree-build")
+ }
queryviewDir := filepath.Join(config.SoongOutDir(), "queryview")
// The BUILD files will be generated in out/soong/.api_bp2build (no symlinks to src files)
@@ -497,6 +508,12 @@
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()
diff --git a/ui/build/staging_snapshot.go b/ui/build/staging_snapshot.go
new file mode 100644
index 0000000..377aa64
--- /dev/null
+++ b/ui/build/staging_snapshot.go
@@ -0,0 +1,246 @@
+// 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 build
+
+import (
+ "crypto/sha1"
+ "encoding/hex"
+ "encoding/json"
+ "io"
+ "io/fs"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+
+ "android/soong/shared"
+ "android/soong/ui/metrics"
+)
+
+// Metadata about a staged file
+type fileEntry struct {
+ Name string `json:"name"`
+ Mode fs.FileMode `json:"mode"`
+ Size int64 `json:"size"`
+ Sha1 string `json:"sha1"`
+}
+
+func fileEntryEqual(a fileEntry, b fileEntry) bool {
+ return a.Name == b.Name && a.Mode == b.Mode && a.Size == b.Size && a.Sha1 == b.Sha1
+}
+
+func sha1_hash(filename string) (string, error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+
+ h := sha1.New()
+ if _, err := io.Copy(h, f); err != nil {
+ return "", err
+ }
+
+ return hex.EncodeToString(h.Sum(nil)), nil
+}
+
+// Subdirs of PRODUCT_OUT to scan
+var stagingSubdirs = []string{
+ "apex",
+ "cache",
+ "coverage",
+ "data",
+ "debug_ramdisk",
+ "fake_packages",
+ "installer",
+ "oem",
+ "product",
+ "ramdisk",
+ "recovery",
+ "root",
+ "sysloader",
+ "system",
+ "system_dlkm",
+ "system_ext",
+ "system_other",
+ "testcases",
+ "test_harness_ramdisk",
+ "vendor",
+ "vendor_debug_ramdisk",
+ "vendor_kernel_ramdisk",
+ "vendor_ramdisk",
+}
+
+// Return an array of stagedFileEntrys, one for each file in the staging directories inside
+// productOut
+func takeStagingSnapshot(ctx Context, productOut string, subdirs []string) ([]fileEntry, error) {
+ var outer_err error
+ if !strings.HasSuffix(productOut, "/") {
+ productOut += "/"
+ }
+ result := []fileEntry{}
+ for _, subdir := range subdirs {
+ filepath.WalkDir(productOut+subdir,
+ func(filename string, dirent fs.DirEntry, err error) error {
+ // Ignore errors. The most common one is that one of the subdirectories
+ // hasn't been built, in which case we just report it as empty.
+ if err != nil {
+ ctx.Verbosef("scanModifiedStagingOutputs error: %s", err)
+ return nil
+ }
+ if dirent.Type().IsRegular() {
+ fileInfo, _ := dirent.Info()
+ relative := strings.TrimPrefix(filename, productOut)
+ sha, err := sha1_hash(filename)
+ if err != nil {
+ outer_err = err
+ }
+ result = append(result, fileEntry{
+ Name: relative,
+ Mode: fileInfo.Mode(),
+ Size: fileInfo.Size(),
+ Sha1: sha,
+ })
+ }
+ return nil
+ })
+ }
+
+ sort.Slice(result, func(l, r int) bool { return result[l].Name < result[r].Name })
+
+ return result, outer_err
+}
+
+// Read json into an array of fileEntry. On error return empty array.
+func readJson(filename string) ([]fileEntry, error) {
+ buf, err := os.ReadFile(filename)
+ if err != nil {
+ // Not an error, just missing, which is empty.
+ return []fileEntry{}, nil
+ }
+
+ var result []fileEntry
+ err = json.Unmarshal(buf, &result)
+ if err != nil {
+ // Bad formatting. This is an error
+ return []fileEntry{}, err
+ }
+
+ return result, nil
+}
+
+// Write obj to filename.
+func writeJson(filename string, obj interface{}) error {
+ buf, err := json.MarshalIndent(obj, "", " ")
+ if err != nil {
+ return err
+ }
+
+ return os.WriteFile(filename, buf, 0660)
+}
+
+type snapshotDiff struct {
+ Added []string `json:"added"`
+ Changed []string `json:"changed"`
+ Removed []string `json:"removed"`
+}
+
+// Diff the two snapshots, returning a snapshotDiff.
+func diffSnapshots(previous []fileEntry, current []fileEntry) snapshotDiff {
+ result := snapshotDiff{
+ Added: []string{},
+ Changed: []string{},
+ Removed: []string{},
+ }
+
+ found := make(map[string]bool)
+
+ prev := make(map[string]fileEntry)
+ for _, pre := range previous {
+ prev[pre.Name] = pre
+ }
+
+ for _, cur := range current {
+ pre, ok := prev[cur.Name]
+ found[cur.Name] = true
+ // Added
+ if !ok {
+ result.Added = append(result.Added, cur.Name)
+ continue
+ }
+ // Changed
+ if !fileEntryEqual(pre, cur) {
+ result.Changed = append(result.Changed, cur.Name)
+ }
+ }
+
+ // Removed
+ for _, pre := range previous {
+ if !found[pre.Name] {
+ result.Removed = append(result.Removed, pre.Name)
+ }
+ }
+
+ // Sort the results
+ sort.Strings(result.Added)
+ sort.Strings(result.Changed)
+ sort.Strings(result.Removed)
+
+ return result
+}
+
+// Write a json files to dist:
+// - A list of which files have changed in this build.
+//
+// And record in out/soong:
+// - A list of all files in the staging directories, including their hashes.
+func runStagingSnapshot(ctx Context, config Config) {
+ ctx.BeginTrace(metrics.RunSoong, "runStagingSnapshot")
+ defer ctx.EndTrace()
+
+ snapshotFilename := shared.JoinPath(config.SoongOutDir(), "staged_files.json")
+
+ // Read the existing snapshot file. If it doesn't exist, this is a full
+ // build, so all files will be treated as new.
+ previous, err := readJson(snapshotFilename)
+ if err != nil {
+ ctx.Fatal(err)
+ return
+ }
+
+ // Take a snapshot of the current out directory
+ current, err := takeStagingSnapshot(ctx, config.ProductOut(), stagingSubdirs)
+ if err != nil {
+ ctx.Fatal(err)
+ return
+ }
+
+ // Diff the snapshots
+ diff := diffSnapshots(previous, current)
+
+ // Write the diff (use RealDistDir, not one that might have been faked for bazel)
+ err = writeJson(shared.JoinPath(config.RealDistDir(), "modified_files.json"), diff)
+ if err != nil {
+ ctx.Fatal(err)
+ return
+ }
+
+ // Update the snapshot
+ err = writeJson(snapshotFilename, current)
+ if err != nil {
+ ctx.Fatal(err)
+ return
+ }
+}
diff --git a/ui/build/staging_snapshot_test.go b/ui/build/staging_snapshot_test.go
new file mode 100644
index 0000000..7ac5443
--- /dev/null
+++ b/ui/build/staging_snapshot_test.go
@@ -0,0 +1,188 @@
+// 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 build
+
+import (
+ "os"
+ "path/filepath"
+ "reflect"
+ "testing"
+)
+
+func assertDeepEqual(t *testing.T, expected interface{}, actual interface{}) {
+ if !reflect.DeepEqual(actual, expected) {
+ t.Fatalf("expected:\n %#v\n actual:\n %#v", expected, actual)
+ }
+}
+
+// Make a temp directory containing the supplied contents
+func makeTempDir(files []string, directories []string, symlinks []string) string {
+ temp, _ := os.MkdirTemp("", "soon_staging_snapshot_test_")
+
+ for _, file := range files {
+ os.MkdirAll(temp+"/"+filepath.Dir(file), 0700)
+ os.WriteFile(temp+"/"+file, []byte(file), 0600)
+ }
+
+ for _, dir := range directories {
+ os.MkdirAll(temp+"/"+dir, 0770)
+ }
+
+ for _, symlink := range symlinks {
+ os.MkdirAll(temp+"/"+filepath.Dir(symlink), 0770)
+ os.Symlink(temp, temp+"/"+symlink)
+ }
+
+ return temp
+}
+
+// If this is a clean build, we won't have any preexisting files, make sure we get back an empty
+// list and not errors.
+func TestEmptyOut(t *testing.T) {
+ ctx := testContext()
+
+ temp := makeTempDir(nil, nil, nil)
+ defer os.RemoveAll(temp)
+
+ actual, _ := takeStagingSnapshot(ctx, temp, []string{"a", "e", "g"})
+
+ expected := []fileEntry{}
+
+ assertDeepEqual(t, expected, actual)
+}
+
+// Make sure only the listed directories are picked up, and only regular files
+func TestNoExtraSubdirs(t *testing.T) {
+ ctx := testContext()
+
+ temp := makeTempDir([]string{"a/b", "a/c", "d", "e/f"}, []string{"g/h"}, []string{"e/symlink"})
+ defer os.RemoveAll(temp)
+
+ actual, _ := takeStagingSnapshot(ctx, temp, []string{"a", "e", "g"})
+
+ expected := []fileEntry{
+ {"a/b", 0600, 3, "3ec69c85a4ff96830024afeef2d4e512181c8f7b"},
+ {"a/c", 0600, 3, "592d70e4e03ee6f6780c71b0bf3b9608dbf1e201"},
+ {"e/f", 0600, 3, "9e164bef74aceede0974b857170100409efe67f1"},
+ }
+
+ assertDeepEqual(t, expected, actual)
+}
+
+// Make sure diff handles empty lists
+func TestDiffEmpty(t *testing.T) {
+ actual := diffSnapshots(nil, []fileEntry{})
+
+ expected := snapshotDiff{
+ Added: []string{},
+ Changed: []string{},
+ Removed: []string{},
+ }
+
+ assertDeepEqual(t, expected, actual)
+}
+
+// Make sure diff handles adding
+func TestDiffAdd(t *testing.T) {
+ actual := diffSnapshots([]fileEntry{
+ {"a", 0600, 1, "1234"},
+ }, []fileEntry{
+ {"a", 0600, 1, "1234"},
+ {"b", 0700, 2, "5678"},
+ })
+
+ expected := snapshotDiff{
+ Added: []string{"b"},
+ Changed: []string{},
+ Removed: []string{},
+ }
+
+ assertDeepEqual(t, expected, actual)
+}
+
+// Make sure diff handles changing mode
+func TestDiffChangeMode(t *testing.T) {
+ actual := diffSnapshots([]fileEntry{
+ {"a", 0600, 1, "1234"},
+ {"b", 0700, 2, "5678"},
+ }, []fileEntry{
+ {"a", 0600, 1, "1234"},
+ {"b", 0600, 2, "5678"},
+ })
+
+ expected := snapshotDiff{
+ Added: []string{},
+ Changed: []string{"b"},
+ Removed: []string{},
+ }
+
+ assertDeepEqual(t, expected, actual)
+}
+
+// Make sure diff handles changing size
+func TestDiffChangeSize(t *testing.T) {
+ actual := diffSnapshots([]fileEntry{
+ {"a", 0600, 1, "1234"},
+ {"b", 0700, 2, "5678"},
+ }, []fileEntry{
+ {"a", 0600, 1, "1234"},
+ {"b", 0700, 3, "5678"},
+ })
+
+ expected := snapshotDiff{
+ Added: []string{},
+ Changed: []string{"b"},
+ Removed: []string{},
+ }
+
+ assertDeepEqual(t, expected, actual)
+}
+
+// Make sure diff handles changing contents
+func TestDiffChangeContents(t *testing.T) {
+ actual := diffSnapshots([]fileEntry{
+ {"a", 0600, 1, "1234"},
+ {"b", 0700, 2, "5678"},
+ }, []fileEntry{
+ {"a", 0600, 1, "1234"},
+ {"b", 0700, 2, "aaaa"},
+ })
+
+ expected := snapshotDiff{
+ Added: []string{},
+ Changed: []string{"b"},
+ Removed: []string{},
+ }
+
+ assertDeepEqual(t, expected, actual)
+}
+
+// Make sure diff handles removing
+func TestDiffRemove(t *testing.T) {
+ actual := diffSnapshots([]fileEntry{
+ {"a", 0600, 1, "1234"},
+ {"b", 0700, 2, "5678"},
+ }, []fileEntry{
+ {"a", 0600, 1, "1234"},
+ })
+
+ expected := snapshotDiff{
+ Added: []string{},
+ Changed: []string{},
+ Removed: []string{"b"},
+ }
+
+ assertDeepEqual(t, expected, actual)
+}
diff --git a/ui/metrics/BUILD.bazel b/ui/metrics/BUILD.bazel
new file mode 100644
index 0000000..15ebb88
--- /dev/null
+++ b/ui/metrics/BUILD.bazel
@@ -0,0 +1,30 @@
+# 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.
+
+load("//build/bazel/rules/python:py_proto.bzl", "py_proto_library")
+
+py_proto_library(
+ name = "metrics-py-proto",
+ visibility = ["//build/bazel/scripts/incremental_build:__pkg__"],
+ deps = [":metrics-proto"],
+)
+
+proto_library(
+ name = "metrics-proto",
+ srcs = [
+ "bp2build_metrics_proto/bp2build_metrics.proto",
+ "metrics_proto/metrics.proto",
+ ],
+ strip_import_prefix = "",
+)
diff --git a/ui/metrics/event.go b/ui/metrics/event.go
index b3a027e..cbdeb27 100644
--- a/ui/metrics/event.go
+++ b/ui/metrics/event.go
@@ -135,8 +135,8 @@
e := t.peek()
e.procResInfo = append(e.procResInfo, &soong_metrics_proto.ProcessResourceInfo{
Name: proto.String(name),
- UserTimeMicros: proto.Uint64(uint64(rusage.Utime.Usec)),
- SystemTimeMicros: proto.Uint64(uint64(rusage.Stime.Usec)),
+ UserTimeMicros: proto.Uint64(uint64(state.UserTime().Microseconds())),
+ SystemTimeMicros: proto.Uint64(uint64(state.SystemTime().Microseconds())),
MinorPageFaults: proto.Uint64(uint64(rusage.Minflt)),
MajorPageFaults: proto.Uint64(uint64(rusage.Majflt)),
// ru_inblock and ru_oublock are measured in blocks of 512 bytes.
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index 717530c..82d11ed 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -39,6 +39,7 @@
"time"
"android/soong/shared"
+
"google.golang.org/protobuf/proto"
soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
@@ -125,6 +126,10 @@
}
}
+func (m *Metrics) SetCriticalPathInfo(criticalPathInfo soong_metrics_proto.CriticalPathInfo) {
+ m.metrics.CriticalPathInfo = &criticalPathInfo
+}
+
// SetFatalOrPanicMessage stores a non-zero exit and the relevant message in the latest event if
// available or the metrics base.
func (m *Metrics) SetFatalOrPanicMessage(errMsg string) {
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index eb8fdc4..4ad4a7b 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -158,6 +158,65 @@
return file_metrics_proto_rawDescGZIP(), []int{0, 1}
}
+type BuildConfig_NinjaWeightListSource int32
+
+const (
+ BuildConfig_NOT_USED BuildConfig_NinjaWeightListSource = 0
+ BuildConfig_NINJA_LOG BuildConfig_NinjaWeightListSource = 1
+ BuildConfig_EVENLY_DISTRIBUTED BuildConfig_NinjaWeightListSource = 2
+)
+
+// Enum value maps for BuildConfig_NinjaWeightListSource.
+var (
+ BuildConfig_NinjaWeightListSource_name = map[int32]string{
+ 0: "NOT_USED",
+ 1: "NINJA_LOG",
+ 2: "EVENLY_DISTRIBUTED",
+ }
+ BuildConfig_NinjaWeightListSource_value = map[string]int32{
+ "NOT_USED": 0,
+ "NINJA_LOG": 1,
+ "EVENLY_DISTRIBUTED": 2,
+ }
+)
+
+func (x BuildConfig_NinjaWeightListSource) Enum() *BuildConfig_NinjaWeightListSource {
+ p := new(BuildConfig_NinjaWeightListSource)
+ *p = x
+ return p
+}
+
+func (x BuildConfig_NinjaWeightListSource) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BuildConfig_NinjaWeightListSource) Descriptor() protoreflect.EnumDescriptor {
+ return file_metrics_proto_enumTypes[2].Descriptor()
+}
+
+func (BuildConfig_NinjaWeightListSource) Type() protoreflect.EnumType {
+ return &file_metrics_proto_enumTypes[2]
+}
+
+func (x BuildConfig_NinjaWeightListSource) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BuildConfig_NinjaWeightListSource) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = BuildConfig_NinjaWeightListSource(num)
+ return nil
+}
+
+// Deprecated: Use BuildConfig_NinjaWeightListSource.Descriptor instead.
+func (BuildConfig_NinjaWeightListSource) EnumDescriptor() ([]byte, []int) {
+ return file_metrics_proto_rawDescGZIP(), []int{1, 0}
+}
+
type ModuleTypeInfo_BuildSystem int32
const (
@@ -191,11 +250,11 @@
}
func (ModuleTypeInfo_BuildSystem) Descriptor() protoreflect.EnumDescriptor {
- return file_metrics_proto_enumTypes[2].Descriptor()
+ return file_metrics_proto_enumTypes[3].Descriptor()
}
func (ModuleTypeInfo_BuildSystem) Type() protoreflect.EnumType {
- return &file_metrics_proto_enumTypes[2]
+ return &file_metrics_proto_enumTypes[3]
}
func (x ModuleTypeInfo_BuildSystem) Number() protoreflect.EnumNumber {
@@ -253,11 +312,11 @@
}
func (ExpConfigFetcher_ConfigStatus) Descriptor() protoreflect.EnumDescriptor {
- return file_metrics_proto_enumTypes[3].Descriptor()
+ return file_metrics_proto_enumTypes[4].Descriptor()
}
func (ExpConfigFetcher_ConfigStatus) Type() protoreflect.EnumType {
- return &file_metrics_proto_enumTypes[3]
+ return &file_metrics_proto_enumTypes[4]
}
func (x ExpConfigFetcher_ConfigStatus) Number() protoreflect.EnumNumber {
@@ -348,6 +407,13 @@
// The error message due to a non-zero exit _only_ if it did not occur in a
// recorded phase of the build.
ErrorMessage *string `protobuf:"bytes,30,opt,name=error_message,json=errorMessage" json:"error_message,omitempty"`
+ // The Git Manifest for the user's branch.
+ ManifestUrl *string `protobuf:"bytes,31,opt,name=manifest_url,json=manifestUrl" json:"manifest_url,omitempty"`
+ // The branch on which the build occurred.
+ // Example: refs/heads/master
+ Branch *string `protobuf:"bytes,32,opt,name=branch" json:"branch,omitempty"`
+ // The metric of critical path in build
+ CriticalPathInfo *CriticalPathInfo `protobuf:"bytes,33,opt,name=critical_path_info,json=criticalPathInfo" json:"critical_path_info,omitempty"`
}
// Default values for MetricsBase fields.
@@ -601,6 +667,27 @@
return ""
}
+func (x *MetricsBase) GetManifestUrl() string {
+ if x != nil && x.ManifestUrl != nil {
+ return *x.ManifestUrl
+ }
+ return ""
+}
+
+func (x *MetricsBase) GetBranch() string {
+ if x != nil && x.Branch != nil {
+ return *x.Branch
+ }
+ return ""
+}
+
+func (x *MetricsBase) GetCriticalPathInfo() *CriticalPathInfo {
+ if x != nil {
+ return x.CriticalPathInfo
+ }
+ return nil
+}
+
type BuildConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -619,8 +706,17 @@
Targets []string `protobuf:"bytes,6,rep,name=targets" json:"targets,omitempty"`
// Whether the user explicitly disabled bazel mixed builds for this build.
ForceDisableBazelMixedBuild *bool `protobuf:"varint,7,opt,name=force_disable_bazel_mixed_build,json=forceDisableBazelMixedBuild" json:"force_disable_bazel_mixed_build,omitempty"`
+ // NOT_USED - ninja doesn't use weight list.
+ // NINJA_LOG - ninja uses weight list based on previous builds by ninja log
+ // EVENLY_DISTRIBUTED - ninja thinks every task has the same weight.
+ NinjaWeightListSource *BuildConfig_NinjaWeightListSource `protobuf:"varint,8,opt,name=ninja_weight_list_source,json=ninjaWeightListSource,enum=soong_build_metrics.BuildConfig_NinjaWeightListSource,def=0" json:"ninja_weight_list_source,omitempty"`
}
+// Default values for BuildConfig fields.
+const (
+ Default_BuildConfig_NinjaWeightListSource = BuildConfig_NOT_USED
+)
+
func (x *BuildConfig) Reset() {
*x = BuildConfig{}
if protoimpl.UnsafeEnabled {
@@ -702,6 +798,13 @@
return false
}
+func (x *BuildConfig) GetNinjaWeightListSource() BuildConfig_NinjaWeightListSource {
+ if x != nil && x.NinjaWeightListSource != nil {
+ return *x.NinjaWeightListSource
+ }
+ return Default_BuildConfig_NinjaWeightListSource
+}
+
type SystemResourceInfo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -1409,12 +1512,146 @@
return nil
}
+// CriticalPathInfo contains critical path nodes's information.
+// A critical path is a path determining the minimum time needed for the whole build given perfect parallelism.
+type CriticalPathInfo struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Real time which the build system spent in microseconds
+ ElapsedTimeMicros *uint64 `protobuf:"varint,1,opt,name=elapsed_time_micros,json=elapsedTimeMicros" json:"elapsed_time_micros,omitempty"`
+ // The sum of execution time of the longest path from leave to the root in microseconds
+ CriticalPathTimeMicros *uint64 `protobuf:"varint,2,opt,name=critical_path_time_micros,json=criticalPathTimeMicros" json:"critical_path_time_micros,omitempty"`
+ // Detailed job information in a critical path.
+ CriticalPath []*JobInfo `protobuf:"bytes,4,rep,name=critical_path,json=criticalPath" json:"critical_path,omitempty"`
+ // Detailed job information for long running jobs (>30 seconds). These may or may not also be on a critical path.
+ LongRunningJobs []*JobInfo `protobuf:"bytes,5,rep,name=long_running_jobs,json=longRunningJobs" json:"long_running_jobs,omitempty"`
+}
+
+func (x *CriticalPathInfo) Reset() {
+ *x = CriticalPathInfo{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_metrics_proto_msgTypes[11]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CriticalPathInfo) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CriticalPathInfo) ProtoMessage() {}
+
+func (x *CriticalPathInfo) ProtoReflect() protoreflect.Message {
+ mi := &file_metrics_proto_msgTypes[11]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CriticalPathInfo.ProtoReflect.Descriptor instead.
+func (*CriticalPathInfo) Descriptor() ([]byte, []int) {
+ return file_metrics_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *CriticalPathInfo) GetElapsedTimeMicros() uint64 {
+ if x != nil && x.ElapsedTimeMicros != nil {
+ return *x.ElapsedTimeMicros
+ }
+ return 0
+}
+
+func (x *CriticalPathInfo) GetCriticalPathTimeMicros() uint64 {
+ if x != nil && x.CriticalPathTimeMicros != nil {
+ return *x.CriticalPathTimeMicros
+ }
+ return 0
+}
+
+func (x *CriticalPathInfo) GetCriticalPath() []*JobInfo {
+ if x != nil {
+ return x.CriticalPath
+ }
+ return nil
+}
+
+func (x *CriticalPathInfo) GetLongRunningJobs() []*JobInfo {
+ if x != nil {
+ return x.LongRunningJobs
+ }
+ return nil
+}
+
+type JobInfo struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Real time which a job spent in microseconds
+ ElapsedTimeMicros *uint64 `protobuf:"varint,1,opt,name=elapsed_time_micros,json=elapsedTimeMicros" json:"elapsed_time_micros,omitempty"`
+ // Description of a job
+ JobDescription *string `protobuf:"bytes,2,opt,name=job_description,json=jobDescription" json:"job_description,omitempty"`
+}
+
+func (x *JobInfo) Reset() {
+ *x = JobInfo{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_metrics_proto_msgTypes[12]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *JobInfo) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*JobInfo) ProtoMessage() {}
+
+func (x *JobInfo) ProtoReflect() protoreflect.Message {
+ mi := &file_metrics_proto_msgTypes[12]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use JobInfo.ProtoReflect.Descriptor instead.
+func (*JobInfo) Descriptor() ([]byte, []int) {
+ return file_metrics_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *JobInfo) GetElapsedTimeMicros() uint64 {
+ if x != nil && x.ElapsedTimeMicros != nil {
+ return *x.ElapsedTimeMicros
+ }
+ return 0
+}
+
+func (x *JobInfo) GetJobDescription() string {
+ if x != nil && x.JobDescription != nil {
+ return *x.JobDescription
+ }
+ return ""
+}
+
var File_metrics_proto protoreflect.FileDescriptor
var file_metrics_proto_rawDesc = []byte{
0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x13, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
- 0x72, 0x69, 0x63, 0x73, 0x22, 0xfa, 0x0d, 0x0a, 0x0b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
+ 0x72, 0x69, 0x63, 0x73, 0x22, 0x8a, 0x0f, 0x0a, 0x0b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
0x42, 0x61, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x61,
0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01,
0x28, 0x03, 0x52, 0x12, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d,
@@ -1519,14 +1756,23 @@
0x0b, 0x6e, 0x6f, 0x6e, 0x5a, 0x65, 0x72, 0x6f, 0x45, 0x78, 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d,
0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x1e, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
- 0x65, 0x22, 0x30, 0x0a, 0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x56, 0x61, 0x72, 0x69, 0x61, 0x6e,
+ 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x5f, 0x75, 0x72,
+ 0x6c, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73,
+ 0x74, 0x55, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x18, 0x20,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, 0x53, 0x0a, 0x12,
+ 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x69, 0x6e,
+ 0x66, 0x6f, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
+ 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43,
+ 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52,
+ 0x10, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66,
+ 0x6f, 0x22, 0x30, 0x0a, 0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x56, 0x61, 0x72, 0x69, 0x61, 0x6e,
0x74, 0x12, 0x08, 0x0a, 0x04, 0x55, 0x53, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x55,
0x53, 0x45, 0x52, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x45, 0x4e,
0x47, 0x10, 0x02, 0x22, 0x3c, 0x0a, 0x04, 0x41, 0x72, 0x63, 0x68, 0x12, 0x0b, 0x0a, 0x07, 0x55,
0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x52, 0x4d, 0x10,
0x01, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x52, 0x4d, 0x36, 0x34, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03,
0x58, 0x38, 0x36, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x58, 0x38, 0x36, 0x5f, 0x36, 0x34, 0x10,
- 0x04, 0x22, 0x99, 0x02, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+ 0x04, 0x22, 0xe2, 0x03, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x12, 0x19, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61, 0x18, 0x01, 0x20,
0x01, 0x28, 0x08, 0x52, 0x07, 0x75, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x17, 0x0a, 0x07,
0x75, 0x73, 0x65, 0x5f, 0x72, 0x62, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x75,
@@ -1543,137 +1789,173 @@
0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d,
0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08,
0x52, 0x1b, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61,
- 0x7a, 0x65, 0x6c, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x22, 0x6f, 0x0a,
- 0x12, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49,
- 0x6e, 0x66, 0x6f, 0x12, 0x32, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x68, 0x79,
- 0x73, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x04, 0x52, 0x13, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61,
- 0x6c, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c,
- 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x70, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52,
- 0x0d, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x70, 0x75, 0x73, 0x22, 0xca,
- 0x02, 0x0a, 0x08, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x0a, 0x0b, 0x64,
- 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a,
- 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
- 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18,
- 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65,
- 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20,
- 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, 0x0a,
- 0x0a, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28,
- 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x73, 0x65,
- 0x12, 0x60, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x5f, 0x72, 0x65,
- 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x03, 0x28,
- 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f,
- 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52,
- 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x15, 0x70, 0x72, 0x6f,
- 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e,
- 0x66, 0x6f, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x6f, 0x6e, 0x5f, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x65,
- 0x78, 0x69, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f, 0x6e, 0x5a, 0x65,
- 0x72, 0x6f, 0x45, 0x78, 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f,
- 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65,
- 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb9, 0x03, 0x0a, 0x13,
- 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49,
- 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f,
- 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f,
- 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65,
- 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x73,
- 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12,
- 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f, 0x6b, 0x62, 0x18, 0x04, 0x20,
- 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73, 0x4b, 0x62, 0x12, 0x2a, 0x0a,
- 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c,
- 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x50,
- 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x61, 0x6a,
- 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x06,
- 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46,
- 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f, 0x5f, 0x69, 0x6e, 0x70, 0x75,
- 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6f, 0x49, 0x6e,
- 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f, 0x5f, 0x6f, 0x75, 0x74, 0x70,
- 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x69, 0x6f, 0x4f,
- 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a, 0x76, 0x6f, 0x6c, 0x75, 0x6e,
- 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69,
- 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x18, 0x76, 0x6f, 0x6c,
- 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69,
- 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e,
- 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69,
- 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a, 0x69, 0x6e, 0x76,
- 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53,
- 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a, 0x0e, 0x4d, 0x6f, 0x64, 0x75,
- 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x5b, 0x0a, 0x0c, 0x62, 0x75,
- 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
- 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
- 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70,
- 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65,
- 0x6d, 0x3a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x52, 0x0b, 0x62, 0x75, 0x69, 0x6c,
- 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
- 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f,
- 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x5f,
- 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d,
- 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x2f,
- 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x0b, 0x0a,
- 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x4f,
- 0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41, 0x4b, 0x45, 0x10, 0x02, 0x22,
- 0x6c, 0x0a, 0x1a, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a,
- 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a,
- 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
- 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x01,
- 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
- 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
- 0x42, 0x61, 0x73, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x62, 0x0a,
- 0x1b, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75,
- 0x72, 0x6e, 0x65, 0x79, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x43, 0x0a, 0x04,
- 0x63, 0x75, 0x6a, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f,
+ 0x7a, 0x65, 0x6c, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x79, 0x0a,
+ 0x18, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x6c, 0x69,
+ 0x73, 0x74, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32,
+ 0x36, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+ 0x67, 0x2e, 0x4e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73,
+ 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3a, 0x08, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x53, 0x45,
+ 0x44, 0x52, 0x15, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69,
+ 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x4c, 0x0a, 0x15, 0x4e, 0x69, 0x6e, 0x6a,
+ 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63,
+ 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x53, 0x45, 0x44, 0x10, 0x00, 0x12,
+ 0x0d, 0x0a, 0x09, 0x4e, 0x49, 0x4e, 0x4a, 0x41, 0x5f, 0x4c, 0x4f, 0x47, 0x10, 0x01, 0x12, 0x16,
+ 0x0a, 0x12, 0x45, 0x56, 0x45, 0x4e, 0x4c, 0x59, 0x5f, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42,
+ 0x55, 0x54, 0x45, 0x44, 0x10, 0x02, 0x22, 0x6f, 0x0a, 0x12, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d,
+ 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x32, 0x0a, 0x15,
+ 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x6d,
+ 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x74, 0x6f, 0x74,
+ 0x61, 0x6c, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79,
+ 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x70,
+ 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61,
+ 0x62, 0x6c, 0x65, 0x43, 0x70, 0x75, 0x73, 0x22, 0xca, 0x02, 0x0a, 0x08, 0x50, 0x65, 0x72, 0x66,
+ 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
+ 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
+ 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74,
+ 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09,
+ 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61,
+ 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x65,
+ 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79,
+ 0x5f, 0x75, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09,
+ 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x17, 0x70, 0x72, 0x6f,
+ 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f,
+ 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x6f, 0x6f,
0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
- 0x2e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75,
- 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x04, 0x63, 0x75, 0x6a,
- 0x73, 0x22, 0xcc, 0x02, 0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, 0x67, 0x42, 0x75, 0x69, 0x6c, 0x64,
- 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
- 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
- 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20,
- 0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x0a,
- 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x63, 0x6f, 0x75,
- 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41,
- 0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x74,
- 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20,
- 0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x53,
- 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x65, 0x61, 0x70, 0x5f,
- 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x48,
- 0x65, 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74,
- 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
- 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65,
- 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x50,
- 0x0a, 0x11, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x5f, 0x69,
- 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x6f, 0x6f, 0x6e,
+ 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+ 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x15, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52,
+ 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x0a, 0x0d, 0x6e,
+ 0x6f, 0x6e, 0x5f, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x18, 0x07, 0x20, 0x01,
+ 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f, 0x6e, 0x5a, 0x65, 0x72, 0x6f, 0x45, 0x78, 0x69, 0x74, 0x12,
+ 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+ 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73,
+ 0x73, 0x61, 0x67, 0x65, 0x22, 0xb9, 0x03, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
+ 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04,
+ 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+ 0x12, 0x28, 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69,
+ 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72,
+ 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79,
+ 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69,
+ 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f,
+ 0x72, 0x73, 0x73, 0x5f, 0x6b, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61,
+ 0x78, 0x52, 0x73, 0x73, 0x4b, 0x62, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f,
+ 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28,
+ 0x04, 0x52, 0x0f, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c,
+ 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65,
+ 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d,
+ 0x61, 0x6a, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e,
+ 0x0a, 0x0b, 0x69, 0x6f, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x07, 0x20,
+ 0x01, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20,
+ 0x0a, 0x0c, 0x69, 0x6f, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x08,
+ 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62,
+ 0x12, 0x3c, 0x0a, 0x1a, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f,
+ 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x09,
+ 0x20, 0x01, 0x28, 0x04, 0x52, 0x18, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43,
+ 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40,
+ 0x0a, 0x1c, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f,
+ 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a,
+ 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72,
+ 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73,
+ 0x22, 0xe5, 0x01, 0x0a, 0x0e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49,
+ 0x6e, 0x66, 0x6f, 0x12, 0x5b, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x79, 0x73,
+ 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e,
0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
- 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52,
- 0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f,
- 0x22, 0xdb, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65,
- 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
- 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x43,
- 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e,
- 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
- 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a,
- 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d,
- 0x69, 0x63, 0x72, 0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53,
- 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x43, 0x4f, 0x4e, 0x46,
- 0x49, 0x47, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01,
- 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4d,
- 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54, 0x10, 0x03, 0x22, 0x91,
- 0x01, 0x0a, 0x0f, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e,
- 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c,
- 0x64, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
- 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75,
- 0x69, 0x6c, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
- 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
- 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
- 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75,
- 0x69, 0x6c, 0x64, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c,
- 0x65, 0x73, 0x42, 0x28, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f,
- 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6d,
- 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x42,
+ 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x07, 0x55, 0x4e, 0x4b, 0x4e,
+ 0x4f, 0x57, 0x4e, 0x52, 0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d,
+ 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70,
+ 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x75,
+ 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4f, 0x66,
+ 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64,
+ 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57,
+ 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08,
+ 0x0a, 0x04, 0x4d, 0x41, 0x4b, 0x45, 0x10, 0x02, 0x22, 0x6c, 0x0a, 0x1a, 0x43, 0x72, 0x69, 0x74,
+ 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d,
+ 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f,
+ 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+ 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, 0x52, 0x07, 0x6d,
+ 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x62, 0x0a, 0x1b, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63,
+ 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x73, 0x4d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x43, 0x0a, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x18, 0x01, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c,
+ 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63,
+ 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74,
+ 0x72, 0x69, 0x63, 0x73, 0x52, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x22, 0xcc, 0x02, 0x0a, 0x11, 0x53,
+ 0x6f, 0x6f, 0x6e, 0x67, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
+ 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x0d, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61,
+ 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x61,
+ 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f,
+ 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x04, 0x52, 0x0f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x75,
+ 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f,
+ 0x63, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x6f,
+ 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0d,
+ 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20,
+ 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x48, 0x65, 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65,
+ 0x12, 0x35, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b,
+ 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
+ 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52,
+ 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x11, 0x6d, 0x69, 0x78, 0x65, 0x64,
+ 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
+ 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75,
+ 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42,
+ 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0xdb, 0x01, 0x0a, 0x10, 0x45, 0x78,
+ 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x4a,
+ 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32,
+ 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
+ 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65,
+ 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74,
+ 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69,
+ 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69,
+ 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x22, 0x47,
+ 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d,
+ 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x00, 0x12, 0x0a, 0x0a,
+ 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52,
+ 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f,
+ 0x47, 0x43, 0x45, 0x52, 0x54, 0x10, 0x03, 0x22, 0x91, 0x01, 0x0a, 0x0f, 0x4d, 0x69, 0x78, 0x65,
+ 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x6d,
+ 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c,
+ 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09,
+ 0x52, 0x18, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x45, 0x6e, 0x61, 0x62,
+ 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x6d, 0x69,
+ 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c,
+ 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
+ 0x52, 0x19, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x69, 0x73, 0x61,
+ 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x8a, 0x02, 0x0a, 0x10,
+ 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f,
+ 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65,
+ 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65,
+ 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73,
+ 0x12, 0x39, 0x0a, 0x19, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74,
+ 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x04, 0x52, 0x16, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74,
+ 0x68, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x41, 0x0a, 0x0d, 0x63,
+ 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x03,
+ 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
+ 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f,
+ 0x52, 0x0c, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x48,
+ 0x0a, 0x11, 0x6c, 0x6f, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6a,
+ 0x6f, 0x62, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e,
+ 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
+ 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e,
+ 0x6e, 0x69, 0x6e, 0x67, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x62, 0x0a, 0x07, 0x4a, 0x6f, 0x62, 0x49,
+ 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74,
+ 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
+ 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63,
+ 0x72, 0x6f, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6a, 0x6f, 0x62, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72,
+ 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6a, 0x6f,
+ 0x62, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x28, 0x5a, 0x26,
+ 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69,
+ 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
+ 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
}
var (
@@ -1688,52 +1970,59 @@
return file_metrics_proto_rawDescData
}
-var file_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
-var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
+var file_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
+var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
var file_metrics_proto_goTypes = []interface{}{
- (MetricsBase_BuildVariant)(0), // 0: soong_build_metrics.MetricsBase.BuildVariant
- (MetricsBase_Arch)(0), // 1: soong_build_metrics.MetricsBase.Arch
- (ModuleTypeInfo_BuildSystem)(0), // 2: soong_build_metrics.ModuleTypeInfo.BuildSystem
- (ExpConfigFetcher_ConfigStatus)(0), // 3: soong_build_metrics.ExpConfigFetcher.ConfigStatus
- (*MetricsBase)(nil), // 4: soong_build_metrics.MetricsBase
- (*BuildConfig)(nil), // 5: soong_build_metrics.BuildConfig
- (*SystemResourceInfo)(nil), // 6: soong_build_metrics.SystemResourceInfo
- (*PerfInfo)(nil), // 7: soong_build_metrics.PerfInfo
- (*ProcessResourceInfo)(nil), // 8: soong_build_metrics.ProcessResourceInfo
- (*ModuleTypeInfo)(nil), // 9: soong_build_metrics.ModuleTypeInfo
- (*CriticalUserJourneyMetrics)(nil), // 10: soong_build_metrics.CriticalUserJourneyMetrics
- (*CriticalUserJourneysMetrics)(nil), // 11: soong_build_metrics.CriticalUserJourneysMetrics
- (*SoongBuildMetrics)(nil), // 12: soong_build_metrics.SoongBuildMetrics
- (*ExpConfigFetcher)(nil), // 13: soong_build_metrics.ExpConfigFetcher
- (*MixedBuildsInfo)(nil), // 14: soong_build_metrics.MixedBuildsInfo
+ (MetricsBase_BuildVariant)(0), // 0: soong_build_metrics.MetricsBase.BuildVariant
+ (MetricsBase_Arch)(0), // 1: soong_build_metrics.MetricsBase.Arch
+ (BuildConfig_NinjaWeightListSource)(0), // 2: soong_build_metrics.BuildConfig.NinjaWeightListSource
+ (ModuleTypeInfo_BuildSystem)(0), // 3: soong_build_metrics.ModuleTypeInfo.BuildSystem
+ (ExpConfigFetcher_ConfigStatus)(0), // 4: soong_build_metrics.ExpConfigFetcher.ConfigStatus
+ (*MetricsBase)(nil), // 5: soong_build_metrics.MetricsBase
+ (*BuildConfig)(nil), // 6: soong_build_metrics.BuildConfig
+ (*SystemResourceInfo)(nil), // 7: soong_build_metrics.SystemResourceInfo
+ (*PerfInfo)(nil), // 8: soong_build_metrics.PerfInfo
+ (*ProcessResourceInfo)(nil), // 9: soong_build_metrics.ProcessResourceInfo
+ (*ModuleTypeInfo)(nil), // 10: soong_build_metrics.ModuleTypeInfo
+ (*CriticalUserJourneyMetrics)(nil), // 11: soong_build_metrics.CriticalUserJourneyMetrics
+ (*CriticalUserJourneysMetrics)(nil), // 12: soong_build_metrics.CriticalUserJourneysMetrics
+ (*SoongBuildMetrics)(nil), // 13: soong_build_metrics.SoongBuildMetrics
+ (*ExpConfigFetcher)(nil), // 14: soong_build_metrics.ExpConfigFetcher
+ (*MixedBuildsInfo)(nil), // 15: soong_build_metrics.MixedBuildsInfo
+ (*CriticalPathInfo)(nil), // 16: soong_build_metrics.CriticalPathInfo
+ (*JobInfo)(nil), // 17: soong_build_metrics.JobInfo
}
var file_metrics_proto_depIdxs = []int32{
0, // 0: soong_build_metrics.MetricsBase.target_build_variant:type_name -> soong_build_metrics.MetricsBase.BuildVariant
1, // 1: soong_build_metrics.MetricsBase.target_arch:type_name -> soong_build_metrics.MetricsBase.Arch
1, // 2: soong_build_metrics.MetricsBase.host_arch:type_name -> soong_build_metrics.MetricsBase.Arch
1, // 3: soong_build_metrics.MetricsBase.host_2nd_arch:type_name -> soong_build_metrics.MetricsBase.Arch
- 7, // 4: soong_build_metrics.MetricsBase.setup_tools:type_name -> soong_build_metrics.PerfInfo
- 7, // 5: soong_build_metrics.MetricsBase.kati_runs:type_name -> soong_build_metrics.PerfInfo
- 7, // 6: soong_build_metrics.MetricsBase.soong_runs:type_name -> soong_build_metrics.PerfInfo
- 7, // 7: soong_build_metrics.MetricsBase.ninja_runs:type_name -> soong_build_metrics.PerfInfo
- 7, // 8: soong_build_metrics.MetricsBase.total:type_name -> soong_build_metrics.PerfInfo
- 12, // 9: soong_build_metrics.MetricsBase.soong_build_metrics:type_name -> soong_build_metrics.SoongBuildMetrics
- 5, // 10: soong_build_metrics.MetricsBase.build_config:type_name -> soong_build_metrics.BuildConfig
- 6, // 11: soong_build_metrics.MetricsBase.system_resource_info:type_name -> soong_build_metrics.SystemResourceInfo
- 7, // 12: soong_build_metrics.MetricsBase.bazel_runs:type_name -> soong_build_metrics.PerfInfo
- 13, // 13: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher
- 8, // 14: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo
- 2, // 15: soong_build_metrics.ModuleTypeInfo.build_system:type_name -> soong_build_metrics.ModuleTypeInfo.BuildSystem
- 4, // 16: soong_build_metrics.CriticalUserJourneyMetrics.metrics:type_name -> soong_build_metrics.MetricsBase
- 10, // 17: soong_build_metrics.CriticalUserJourneysMetrics.cujs:type_name -> soong_build_metrics.CriticalUserJourneyMetrics
- 7, // 18: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo
- 14, // 19: soong_build_metrics.SoongBuildMetrics.mixed_builds_info:type_name -> soong_build_metrics.MixedBuildsInfo
- 3, // 20: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus
- 21, // [21:21] is the sub-list for method output_type
- 21, // [21:21] is the sub-list for method input_type
- 21, // [21:21] is the sub-list for extension type_name
- 21, // [21:21] is the sub-list for extension extendee
- 0, // [0:21] is the sub-list for field type_name
+ 8, // 4: soong_build_metrics.MetricsBase.setup_tools:type_name -> soong_build_metrics.PerfInfo
+ 8, // 5: soong_build_metrics.MetricsBase.kati_runs:type_name -> soong_build_metrics.PerfInfo
+ 8, // 6: soong_build_metrics.MetricsBase.soong_runs:type_name -> soong_build_metrics.PerfInfo
+ 8, // 7: soong_build_metrics.MetricsBase.ninja_runs:type_name -> soong_build_metrics.PerfInfo
+ 8, // 8: soong_build_metrics.MetricsBase.total:type_name -> soong_build_metrics.PerfInfo
+ 13, // 9: soong_build_metrics.MetricsBase.soong_build_metrics:type_name -> soong_build_metrics.SoongBuildMetrics
+ 6, // 10: soong_build_metrics.MetricsBase.build_config:type_name -> soong_build_metrics.BuildConfig
+ 7, // 11: soong_build_metrics.MetricsBase.system_resource_info:type_name -> soong_build_metrics.SystemResourceInfo
+ 8, // 12: soong_build_metrics.MetricsBase.bazel_runs:type_name -> soong_build_metrics.PerfInfo
+ 14, // 13: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher
+ 16, // 14: soong_build_metrics.MetricsBase.critical_path_info:type_name -> soong_build_metrics.CriticalPathInfo
+ 2, // 15: soong_build_metrics.BuildConfig.ninja_weight_list_source:type_name -> soong_build_metrics.BuildConfig.NinjaWeightListSource
+ 9, // 16: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo
+ 3, // 17: soong_build_metrics.ModuleTypeInfo.build_system:type_name -> soong_build_metrics.ModuleTypeInfo.BuildSystem
+ 5, // 18: soong_build_metrics.CriticalUserJourneyMetrics.metrics:type_name -> soong_build_metrics.MetricsBase
+ 11, // 19: soong_build_metrics.CriticalUserJourneysMetrics.cujs:type_name -> soong_build_metrics.CriticalUserJourneyMetrics
+ 8, // 20: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo
+ 15, // 21: soong_build_metrics.SoongBuildMetrics.mixed_builds_info:type_name -> soong_build_metrics.MixedBuildsInfo
+ 4, // 22: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus
+ 17, // 23: soong_build_metrics.CriticalPathInfo.critical_path:type_name -> soong_build_metrics.JobInfo
+ 17, // 24: soong_build_metrics.CriticalPathInfo.long_running_jobs:type_name -> soong_build_metrics.JobInfo
+ 25, // [25:25] is the sub-list for method output_type
+ 25, // [25:25] is the sub-list for method input_type
+ 25, // [25:25] is the sub-list for extension type_name
+ 25, // [25:25] is the sub-list for extension extendee
+ 0, // [0:25] is the sub-list for field type_name
}
func init() { file_metrics_proto_init() }
@@ -1874,14 +2163,38 @@
return nil
}
}
+ file_metrics_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*CriticalPathInfo); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_metrics_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*JobInfo); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_metrics_proto_rawDesc,
- NumEnums: 4,
- NumMessages: 11,
+ NumEnums: 5,
+ NumMessages: 13,
NumExtensions: 0,
NumServices: 0,
},
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index 5ad13fc..5e9a055 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -121,9 +121,25 @@
// The error message due to a non-zero exit _only_ if it did not occur in a
// recorded phase of the build.
optional string error_message = 30;
+
+ // The Git Manifest for the user's branch.
+ optional string manifest_url = 31;
+
+ // The branch on which the build occurred.
+ // Example: refs/heads/master
+ optional string branch = 32;
+
+ // The metric of critical path in build
+ optional CriticalPathInfo critical_path_info = 33;
}
message BuildConfig {
+ enum NinjaWeightListSource {
+ NOT_USED = 0;
+ NINJA_LOG = 1;
+ EVENLY_DISTRIBUTED = 2;
+ }
+
optional bool use_goma = 1;
optional bool use_rbe = 2;
@@ -143,6 +159,11 @@
// Whether the user explicitly disabled bazel mixed builds for this build.
optional bool force_disable_bazel_mixed_build = 7;
+
+ // NOT_USED - ninja doesn't use weight list.
+ // NINJA_LOG - ninja uses weight list based on previous builds by ninja log
+ // EVENLY_DISTRIBUTED - ninja thinks every task has the same weight.
+ optional NinjaWeightListSource ninja_weight_list_source = 8 [default = NOT_USED];
}
message SystemResourceInfo {
@@ -307,3 +328,23 @@
// Modules that are not enabled for MixedBuilds
repeated string mixed_build_disabled_modules = 2;
}
+
+// CriticalPathInfo contains critical path nodes's information.
+// A critical path is a path determining the minimum time needed for the whole build given perfect parallelism.
+message CriticalPathInfo {
+ // Real time which the build system spent in microseconds
+ optional uint64 elapsed_time_micros = 1;
+ // The sum of execution time of the longest path from leave to the root in microseconds
+ optional uint64 critical_path_time_micros = 2;
+ // Detailed job information in a critical path.
+ repeated JobInfo critical_path = 4;
+ // Detailed job information for long running jobs (>30 seconds). These may or may not also be on a critical path.
+ repeated JobInfo long_running_jobs = 5;
+}
+
+message JobInfo {
+ // Real time which a job spent in microseconds
+ optional uint64 elapsed_time_micros = 1;
+ // Description of a job
+ optional string job_description = 2;
+}
diff --git a/ui/status/Android.bp b/ui/status/Android.bp
index a46a007..b724bc9 100644
--- a/ui/status/Android.bp
+++ b/ui/status/Android.bp
@@ -28,6 +28,7 @@
],
srcs: [
"critical_path.go",
+ "critical_path_logger.go",
"kati.go",
"log.go",
"ninja.go",
diff --git a/ui/status/critical_path.go b/ui/status/critical_path.go
index 8065c60..bf32c58 100644
--- a/ui/status/critical_path.go
+++ b/ui/status/critical_path.go
@@ -15,23 +15,23 @@
package status
import (
+ "android/soong/ui/metrics"
+
+ soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
"time"
- "android/soong/ui/logger"
+ "google.golang.org/protobuf/proto"
)
-func NewCriticalPath(log logger.Logger) StatusOutput {
- return &criticalPath{
- log: log,
+func NewCriticalPath() *CriticalPath {
+ return &CriticalPath{
running: make(map[*Action]time.Time),
nodes: make(map[string]*node),
clock: osClock{},
}
}
-type criticalPath struct {
- log logger.Logger
-
+type CriticalPath struct {
nodes map[string]*node
running map[*Action]time.Time
@@ -57,7 +57,7 @@
input *node
}
-func (cp *criticalPath) StartAction(action *Action, counts Counts) {
+func (cp *CriticalPath) StartAction(action *Action) {
start := cp.clock.Now()
if cp.start.IsZero() {
cp.start = start
@@ -65,13 +65,13 @@
cp.running[action] = start
}
-func (cp *criticalPath) FinishAction(result ActionResult, counts Counts) {
- if start, ok := cp.running[result.Action]; ok {
- delete(cp.running, result.Action)
+func (cp *CriticalPath) FinishAction(action *Action) {
+ if start, ok := cp.running[action]; ok {
+ delete(cp.running, action)
// Determine the input to this edge with the longest cumulative duration
var criticalPathInput *node
- for _, input := range result.Action.Inputs {
+ for _, input := range action.Inputs {
if x := cp.nodes[input]; x != nil {
if criticalPathInput == nil || x.cumulativeDuration > criticalPathInput.cumulativeDuration {
criticalPathInput = x
@@ -88,13 +88,13 @@
}
node := &node{
- action: result.Action,
+ action: action,
cumulativeDuration: cumulativeDuration,
duration: duration,
input: criticalPathInput,
}
- for _, output := range result.Action.Outputs {
+ for _, output := range action.Outputs {
cp.nodes[output] = node
}
@@ -102,37 +102,7 @@
}
}
-func (cp *criticalPath) Flush() {
- criticalPath := cp.criticalPath()
-
- if len(criticalPath) > 0 {
- // Log the critical path to the verbose log
- criticalTime := criticalPath[0].cumulativeDuration.Round(time.Second)
- cp.log.Verbosef("critical path took %s", criticalTime.String())
- if !cp.start.IsZero() {
- elapsedTime := cp.end.Sub(cp.start).Round(time.Second)
- cp.log.Verbosef("elapsed time %s", elapsedTime.String())
- if elapsedTime > 0 {
- cp.log.Verbosef("perfect parallelism ratio %d%%",
- int(float64(criticalTime)/float64(elapsedTime)*100))
- }
- }
- cp.log.Verbose("critical path:")
- for i := len(criticalPath) - 1; i >= 0; i-- {
- duration := criticalPath[i].duration
- duration = duration.Round(time.Second)
- seconds := int(duration.Seconds())
- cp.log.Verbosef(" %2d:%02d %s",
- seconds/60, seconds%60, criticalPath[i].action.Description)
- }
- }
-}
-
-func (cp *criticalPath) Message(level MsgLevel, msg string) {}
-
-func (cp *criticalPath) Write(p []byte) (n int, err error) { return len(p), nil }
-
-func (cp *criticalPath) criticalPath() []*node {
+func (cp *CriticalPath) criticalPath() (path []*node, elapsedTime time.Duration, criticalTime time.Duration) {
var max *node
// Find the node with the longest critical path
@@ -142,13 +112,46 @@
}
}
- // Follow the critical path back to the leaf node
- var criticalPath []*node
node := max
for node != nil {
- criticalPath = append(criticalPath, node)
+ path = append(path, node)
node = node.input
}
+ if len(path) > 0 {
+ // Log the critical path to the verbose log
+ criticalTime = path[0].cumulativeDuration
+ if !cp.start.IsZero() {
+ elapsedTime = cp.end.Sub(cp.start)
+ }
+ }
+ return
+}
- return criticalPath
+func (cp *CriticalPath) longRunningJobs() (nodes []*node) {
+ threshold := time.Second * 30
+ for _, node := range cp.nodes {
+ if node != nil && node.duration > threshold {
+ nodes = append(nodes, node)
+ }
+ }
+ return
+}
+
+func addJobInfos(jobInfos *[]*soong_metrics_proto.JobInfo, sources []*node) {
+ for _, job := range sources {
+ jobInfo := soong_metrics_proto.JobInfo{}
+ jobInfo.ElapsedTimeMicros = proto.Uint64(uint64(job.duration.Microseconds()))
+ jobInfo.JobDescription = &job.action.Description
+ *jobInfos = append(*jobInfos, &jobInfo)
+ }
+}
+
+func (cp *CriticalPath) WriteToMetrics(met *metrics.Metrics) {
+ criticalPathInfo := soong_metrics_proto.CriticalPathInfo{}
+ path, elapsedTime, criticalTime := cp.criticalPath()
+ criticalPathInfo.ElapsedTimeMicros = proto.Uint64(uint64(elapsedTime.Microseconds()))
+ criticalPathInfo.CriticalPathTimeMicros = proto.Uint64(uint64(criticalTime.Microseconds()))
+ addJobInfos(&criticalPathInfo.LongRunningJobs, cp.longRunningJobs())
+ addJobInfos(&criticalPathInfo.CriticalPath, path)
+ met.SetCriticalPathInfo(criticalPathInfo)
}
diff --git a/ui/status/critical_path_logger.go b/ui/status/critical_path_logger.go
new file mode 100644
index 0000000..f8b49d1
--- /dev/null
+++ b/ui/status/critical_path_logger.go
@@ -0,0 +1,73 @@
+// 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 status
+
+import (
+ "time"
+
+ "android/soong/ui/logger"
+)
+
+// Create a new CriticalPathLogger. if criticalPath is nil, it creates a new criticalPath,
+// if not, it uses that.(its purpose is using a critical path outside logger)
+func NewCriticalPathLogger(log logger.Logger, criticalPath *CriticalPath) StatusOutput {
+ if criticalPath == nil {
+ criticalPath = NewCriticalPath()
+ }
+ return &criticalPathLogger{
+ log: log,
+ criticalPath: criticalPath,
+ }
+}
+
+type criticalPathLogger struct {
+ log logger.Logger
+ criticalPath *CriticalPath
+}
+
+func (cp *criticalPathLogger) StartAction(action *Action, counts Counts) {
+ cp.criticalPath.StartAction(action)
+}
+
+func (cp *criticalPathLogger) FinishAction(result ActionResult, counts Counts) {
+ cp.criticalPath.FinishAction(result.Action)
+}
+
+func (cp *criticalPathLogger) Flush() {
+ criticalPath, elapsedTime, criticalTime := cp.criticalPath.criticalPath()
+
+ if len(criticalPath) > 0 {
+ cp.log.Verbosef("critical path took %s", criticalTime.String())
+ if !cp.criticalPath.start.IsZero() {
+ cp.log.Verbosef("elapsed time %s", elapsedTime.String())
+ if elapsedTime > 0 {
+ cp.log.Verbosef("perfect parallelism ratio %d%%",
+ int(float64(criticalTime)/float64(elapsedTime)*100))
+ }
+ }
+ cp.log.Verbose("critical path:")
+ for i := len(criticalPath) - 1; i >= 0; i-- {
+ duration := criticalPath[i].duration
+ duration = duration.Round(time.Second)
+ seconds := int(duration.Seconds())
+ cp.log.Verbosef(" %2d:%02d %s",
+ seconds/60, seconds%60, criticalPath[i].action.Description)
+ }
+ }
+}
+
+func (cp *criticalPathLogger) Message(level MsgLevel, msg string) {}
+
+func (cp *criticalPathLogger) Write(p []byte) (n int, err error) { return len(p), nil }
diff --git a/ui/status/critical_path_test.go b/ui/status/critical_path_test.go
index 965e0ad..369e805 100644
--- a/ui/status/critical_path_test.go
+++ b/ui/status/critical_path_test.go
@@ -21,7 +21,7 @@
)
type testCriticalPath struct {
- *criticalPath
+ *CriticalPath
Counts
actions map[int]*Action
@@ -40,14 +40,12 @@
}
t.actions[id] = action
- t.StartAction(action, t.Counts)
+ t.StartAction(action)
}
func (t *testCriticalPath) finish(id int, endTime time.Duration) {
t.clock = testClock(time.Unix(0, 0).Add(endTime))
- t.FinishAction(ActionResult{
- Action: t.actions[id],
- }, t.Counts)
+ t.FinishAction(t.actions[id])
}
func TestCriticalPath(t *testing.T) {
@@ -137,13 +135,13 @@
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cp := &testCriticalPath{
- criticalPath: NewCriticalPath(nil).(*criticalPath),
+ CriticalPath: NewCriticalPath(),
actions: make(map[int]*Action),
}
tt.msgs(cp)
- criticalPath := cp.criticalPath.criticalPath()
+ criticalPath, _, _ := cp.CriticalPath.criticalPath()
var descs []string
for _, x := range criticalPath {