Merge "Add -Xjvm-defaults=all to kotlin compilations"
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index ccfad00..a5cea17 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -39,6 +39,7 @@
Bp2buildDefaultConfig = Bp2BuildConfig{
"prebuilts/runtime/mainline/platform/sdk": Bp2BuildDefaultTrueRecursively,
"art/libartpalette": Bp2BuildDefaultTrueRecursively,
+ "art/libartbase": Bp2BuildDefaultTrueRecursively,
"art/libdexfile": Bp2BuildDefaultTrueRecursively,
"art/libnativebridge": Bp2BuildDefaultTrueRecursively,
"art/runtime": Bp2BuildDefaultTrueRecursively,
@@ -108,6 +109,7 @@
"external/eigen": Bp2BuildDefaultTrueRecursively,
"external/erofs-utils": Bp2BuildDefaultTrueRecursively,
"external/error_prone": Bp2BuildDefaultTrueRecursively,
+ "external/expat": Bp2BuildDefaultTrueRecursively,
"external/f2fs-tools": Bp2BuildDefaultTrue,
"external/flac": Bp2BuildDefaultTrueRecursively,
"external/fmtlib": Bp2BuildDefaultTrueRecursively,
@@ -146,7 +148,7 @@
"external/zlib": Bp2BuildDefaultTrueRecursively,
"external/zopfli": Bp2BuildDefaultTrueRecursively,
"external/zstd": Bp2BuildDefaultTrueRecursively,
- "frameworks/av/media/codecs/g711/decoder": Bp2BuildDefaultTrueRecursively,
+ "frameworks/av/media/codecs": Bp2BuildDefaultTrueRecursively,
"frameworks/av/services/minijail": Bp2BuildDefaultTrueRecursively,
"frameworks/base/media/tests/MediaDump": Bp2BuildDefaultTrue,
"frameworks/base/startop/apps/test": Bp2BuildDefaultTrue,
@@ -280,39 +282,49 @@
"flatbuffer_headers",
"gemmlowp_headers",
"gl_headers",
+ "libandroid_runtime_lazy",
"libandroid_runtime_vm_headers",
"libaudioclient_aidl_conversion_util",
"libaudioutils_fixedfft",
+ "libbinder_headers",
"libbinder_headers_platform_shared",
"libbluetooth-types-header",
+ "libbufferhub_headers",
+ "libcodec2",
"libcodec2_headers",
"libcodec2_internal",
"libdmabufheap",
+ "libdvr_headers",
"libgsm",
"libgui_bufferqueue_sources",
+ "libhardware",
"libhardware_headers",
+ "libincfs_headers",
"libnativeloader-headers",
"libnativewindow_headers",
"libneuralnetworks_headers",
"libopus",
+ "libpdx_headers",
"libprocpartition",
+ "libruy_static",
"libserviceutils",
- "libstagefright_amrnb_common",
- "libstagefright_amrwbdec",
"libstagefright_enc_common",
"libstagefright_foundation_headers",
"libstagefright_headers",
- "libstagefright_m4vh263dec",
- "libstagefright_m4vh263enc",
- "libstagefright_mp3dec_headers",
+ "libsurfaceflinger_headers",
"libsync",
"libtextclassifier_hash_headers",
"libtextclassifier_hash_static",
+ "libtflite_kernel_utils",
+ "libtinyxml2",
"libui-types",
+ "libui_headers",
"libvorbisidec",
"media_ndk_headers",
+ "media_plugin_headers",
"mediaswcodec.policy",
"mediaswcodec.xml",
+ "philox_random",
"philox_random_headers",
"server_configurable_flags",
"tensorflow_headers",
@@ -361,10 +373,13 @@
"gen-kotlin-build-file.py", // TODO(b/198619163) module has same name as source
"libgtest_ndk_c++", "libgtest_main_ndk_c++", // TODO(b/201816222): Requires sdk_version support.
"linkerconfig", "mdnsd", // TODO(b/202876379): has arch-variant static_executable
- "linker", // TODO(b/228316882): cc_binary uses link_crt
- "libdebuggerd", // TODO(b/228314770): support product variable-specific header_libs
- "versioner", // TODO(b/228313961): depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
- "apexer_test", // Requires aapt2
+ "linker", // TODO(b/228316882): cc_binary uses link_crt
+ "libdebuggerd", // TODO(b/228314770): support product variable-specific header_libs
+ "versioner", // TODO(b/228313961): depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
+ "libspeexresampler", // TODO(b/231995978): Filter out unknown cflags
+ "libjpeg", "libvpx", // TODO(b/233948256): Convert .asm files
+ "art_libartbase_headers", // TODO(b/236268577): Header libraries do not support export_shared_libs_headers
+ "apexer_test", // Requires aapt2
"apexer_test_host_tools",
"host_apex_verifier",
@@ -383,6 +398,9 @@
"prebuilt_platform-robolectric-4.4-prebuilt", // aosp/1999250, needs .aar support in Jars
"prebuilt_platform-robolectric-4.5.1-prebuilt", // aosp/1999250, needs .aar support in Jars
+ // proto support
+ "libstats_proto_host", // TODO(b/236055697): handle protos from other packages
+
// path property for filegroups
"conscrypt", // TODO(b/210751803), we don't handle path property for filegroups
"conscrypt-for-host", // TODO(b/210751803), we don't handle path property for filegroups
@@ -451,9 +469,11 @@
"stats-log-api-gen", // depends on unconverted modules: libstats_proto_host
"statslog.cpp", "statslog.h", "statslog.rs", // depends on unconverted modules: stats-log-api-gen
"statslog_art.cpp", "statslog_art.h", "statslog_header.rs", // depends on unconverted modules: stats-log-api-gen
- "timezone-host", // depends on unconverted modules: art.module.api.annotations
- "truth-host-prebuilt", // depends on unconverted modules: truth-prebuilt
- "truth-prebuilt", // depends on unconverted modules: asm-7.0, guava
+ "timezone-host", // depends on unconverted modules: art.module.api.annotations
+ "truth-host-prebuilt", // depends on unconverted modules: truth-prebuilt
+ "truth-prebuilt", // depends on unconverted modules: asm-7.0, guava
+ "libartbase-art-gtest", // depends on unconverted modules: libgtest_isolated, libart, libart-compiler, libdexfile, libprofile
+ "libartbased-art-gtest", // depends on unconverted modules: libgtest_isolated, libartd, libartd-compiler, libdexfiled, libprofiled
// b/215723302; awaiting tz{data,_version} to then rename targets conflicting with srcs
"tzdata",
@@ -463,6 +483,8 @@
Bp2buildCcLibraryStaticOnlyList = []string{}
MixedBuildsDisabledList = []string{
+ "libruy_static", "libtflite_kernel_utils", // TODO(b/237315968); Depend on prebuilt stl, not from source
+
"art_libdexfile_dex_instruction_list_header", // breaks libart_mterp.armng, header not found
"libbrotli", // http://b/198585397, ld.lld: error: bionic/libc/arch-arm64/generic/bionic/memmove.S:95:(.text+0x10): relocation R_AARCH64_CONDBR19 out of range: -1404176 is not in [-1048576, 1048575]; references __memcpy
diff --git a/android/androidmk.go b/android/androidmk.go
index 6b675a6..832c7df 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -945,7 +945,10 @@
return !module.Enabled() ||
module.commonProperties.HideFromMake ||
// Make does not understand LinuxBionic
- module.Os() == LinuxBionic
+ module.Os() == LinuxBionic ||
+ // Make does not understand LinuxMusl, except when we are building with USE_HOST_MUSL=true
+ // and all host binaries are LinuxMusl
+ (module.Os() == LinuxMusl && module.Target().HostCross)
}
// A utility func to format LOCAL_TEST_DATA outputs. See the comments on DataPath to understand how
diff --git a/android/apex.go b/android/apex.go
index 019efdd..c53ceb3 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -836,40 +836,6 @@
ctx.Phony(fmt.Sprintf("%s-depsinfo", ctx.ModuleName()), d.fullListPath, d.flatListPath)
}
-// TODO(b/158059172): remove minSdkVersion allowlist
-var minSdkVersionAllowlist = func(apiMap map[string]int) map[string]ApiLevel {
- list := make(map[string]ApiLevel, len(apiMap))
- for name, finalApiInt := range apiMap {
- list[name] = uncheckedFinalApiLevel(finalApiInt)
- }
- return list
-}(map[string]int{
- "androidx-constraintlayout_constraintlayout-solver-nodeps": 29,
- "apache-commons-compress": 29,
- "bouncycastle_ike_digests": 30,
- "brotli-java": 29,
- "flatbuffer_headers": 30,
- "gemmlowp_headers": 30,
- "ike-internals": 30,
- "libbrotli": 30,
- "libcrypto_static": 30,
- "libeigen": 30,
- "liblz4": 30,
- "libmdnssd": 30,
- "libprocpartition": 30,
- "libprotobuf-java-lite": 30,
- "libprotoutil": 30,
- "libtextclassifier_hash_headers": 30,
- "libtextclassifier_hash_static": 30,
- "libtflite_kernel_utils": 30,
- "libzstd": 30,
- "net-utils-framework-common": 29,
- "philox_random_headers": 30,
- "philox_random": 30,
- "tensorflow_headers": 30,
- "xz-java": 29,
-})
-
// Function called while walking an APEX's payload dependencies.
//
// Return true if the `to` module should be visited, false otherwise.
@@ -921,15 +887,13 @@
}
if err := to.ShouldSupportSdkVersion(ctx, minSdkVersion); err != nil {
toName := ctx.OtherModuleName(to)
- if ver, ok := minSdkVersionAllowlist[toName]; !ok || ver.GreaterThan(minSdkVersion) {
- ctx.OtherModuleErrorf(to, "should support min_sdk_version(%v) for %q: %v."+
- "\n\nDependency path: %s\n\n"+
- "Consider adding 'min_sdk_version: %q' to %q",
- minSdkVersion, ctx.ModuleName(), err.Error(),
- ctx.GetPathString(false),
- minSdkVersion, toName)
- return false
- }
+ ctx.OtherModuleErrorf(to, "should support min_sdk_version(%v) for %q: %v."+
+ "\n\nDependency path: %s\n\n"+
+ "Consider adding 'min_sdk_version: %q' to %q",
+ minSdkVersion, ctx.ModuleName(), err.Error(),
+ ctx.GetPathString(false),
+ minSdkVersion, toName)
+ return false
}
return true
})
diff --git a/android/api_levels.go b/android/api_levels.go
index 8163894..da50b19 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -54,6 +54,14 @@
isPreview bool
}
+func (this ApiLevel) FinalInt() int {
+ if this.IsPreview() {
+ panic("Requested a final int from a non-final ApiLevel")
+ } else {
+ return this.number
+ }
+}
+
func (this ApiLevel) FinalOrFutureInt() int {
if this.IsPreview() {
return FutureApiLevelInt
@@ -184,17 +192,9 @@
// a core-for-system-modules.jar for the module-lib API scope.
var LastWithoutModuleLibCoreSystemModules = uncheckedFinalApiLevel(31)
-// If the `raw` input is the codename of an API level has been finalized, this
-// function returns the API level number associated with that API level. If the
-// input is *not* a finalized codename, the input is returned unmodified.
-//
-// For example, at the time of writing, R has been finalized as API level 30,
-// but S is in development so it has no number assigned. For the following
-// inputs:
-//
-// * "30" -> "30"
-// * "R" -> "30"
-// * "S" -> "S"
+// ReplaceFinalizedCodenames returns the API level number associated with that API level
+// if the `raw` input is the codename of an API level has been finalized.
+// If the input is *not* a finalized codename, the input is returned unmodified.
func ReplaceFinalizedCodenames(config Config, raw string) string {
num, ok := getFinalCodenamesMap(config)[raw]
if !ok {
diff --git a/android/arch.go b/android/arch.go
index 382a7df..e72614c 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -1825,7 +1825,9 @@
for _, t := range targets {
if _, found := set[t.Os.String()]; !found {
set[t.Os.String()] = true
- ret = append(ret, commonTargetMap[t.Os.String()])
+ common := commonTargetMap[t.Os.String()]
+ common.HostCross = t.HostCross
+ ret = append(ret, common)
}
}
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 27255d1..3be9805 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -34,6 +34,21 @@
"android/soong/bazel"
)
+var (
+ writeBazelFile = pctx.AndroidStaticRule("bazelWriteFileRule", blueprint.RuleParams{
+ Command: `sed "s/\\\\n/\n/g" ${out}.rsp >${out}`,
+ Rspfile: "${out}.rsp",
+ RspfileContent: "${content}",
+ }, "content")
+ _ = pctx.HostBinToolVariable("bazelBuildRunfilesTool", "build-runfiles")
+ buildRunfilesRule = pctx.AndroidStaticRule("bazelBuildRunfiles", blueprint.RuleParams{
+ Command: "${bazelBuildRunfilesTool} ${in} ${outDir}",
+ Depfile: "",
+ Description: "",
+ CommandDeps: []string{"${bazelBuildRunfilesTool}"},
+ }, "outDir")
+)
+
func init() {
RegisterMixedBuildsMutator(InitRegistrationContext)
}
@@ -173,26 +188,26 @@
LabelToPythonBinary map[string]string
}
-func (m MockBazelContext) QueueBazelRequest(label string, requestType cqueryRequest, cfgKey configKey) {
+func (m MockBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
panic("unimplemented")
}
-func (m MockBazelContext) GetOutputFiles(label string, cfgKey configKey) ([]string, error) {
+func (m MockBazelContext) GetOutputFiles(label string, _ configKey) ([]string, error) {
result, _ := m.LabelToOutputFiles[label]
return result, nil
}
-func (m MockBazelContext) GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, error) {
+func (m MockBazelContext) GetCcInfo(label string, _ configKey) (cquery.CcInfo, error) {
result, _ := m.LabelToCcInfo[label]
return result, nil
}
-func (m MockBazelContext) GetPythonBinary(label string, cfgKey configKey) (string, error) {
+func (m MockBazelContext) GetPythonBinary(label string, _ configKey) (string, error) {
result, _ := m.LabelToPythonBinary[label]
return result, nil
}
-func (m MockBazelContext) InvokeBazel(config Config) error {
+func (m MockBazelContext) InvokeBazel(_ Config) error {
panic("unimplemented")
}
@@ -246,23 +261,23 @@
return "", fmt.Errorf("no bazel response found for %v", key)
}
-func (n noopBazelContext) QueueBazelRequest(label string, requestType cqueryRequest, cfgKey configKey) {
+func (n noopBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
panic("unimplemented")
}
-func (n noopBazelContext) GetOutputFiles(label string, cfgKey configKey) ([]string, error) {
+func (n noopBazelContext) GetOutputFiles(_ string, _ configKey) ([]string, error) {
panic("unimplemented")
}
-func (n noopBazelContext) GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, error) {
+func (n noopBazelContext) GetCcInfo(_ string, _ configKey) (cquery.CcInfo, error) {
panic("unimplemented")
}
-func (n noopBazelContext) GetPythonBinary(label string, cfgKey configKey) (string, error) {
+func (n noopBazelContext) GetPythonBinary(_ string, _ configKey) (string, error) {
panic("unimplemented")
}
-func (n noopBazelContext) InvokeBazel(config Config) error {
+func (n noopBazelContext) InvokeBazel(_ Config) error {
panic("unimplemented")
}
@@ -304,7 +319,7 @@
p := bazelPaths{
soongOutDir: c.soongOutDir,
}
- missingEnvVars := []string{}
+ var missingEnvVars []string
if len(c.Getenv("BAZEL_HOME")) > 1 {
p.homeDir = c.Getenv("BAZEL_HOME")
} else {
@@ -365,10 +380,8 @@
extraFlags []string
}
-func (r *mockBazelRunner) issueBazelCommand(paths *bazelPaths,
- runName bazel.RunName,
- command bazelCommand,
- extraFlags ...string) (string, string, error) {
+func (r *mockBazelRunner) issueBazelCommand(_ *bazelPaths, _ bazel.RunName,
+ command bazelCommand, extraFlags ...string) (string, string, error) {
r.commands = append(r.commands, command)
r.extraFlags = append(r.extraFlags, strings.Join(extraFlags, " "))
if ret, ok := r.bazelCommandResults[command]; ok {
@@ -396,26 +409,30 @@
command.command,
}
cmdFlags = append(cmdFlags, command.expression)
- cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(paths, runName))
+ cmdFlags = append(cmdFlags,
+ // 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.
- cmdFlags = append(cmdFlags,
- fmt.Sprintf("--platforms=%s", "//build/bazel/platforms:android_target"))
- cmdFlags = append(cmdFlags,
- fmt.Sprintf("--extra_toolchains=%s", "//prebuilts/clang/host/linux-x86:all"))
- // This should be parameterized on the host OS, but let's restrict to linux
- // to keep things simple for now.
- cmdFlags = append(cmdFlags,
- fmt.Sprintf("--host_platform=%s", "//build/bazel/platforms:linux_x86_64"))
+ // 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("--platforms=%s", "//build/bazel/platforms:android_target"),
+ fmt.Sprintf("--extra_toolchains=%s", "//prebuilts/clang/host/linux-x86:all"),
- // Explicitly disable downloading rules (such as canonical C++ and Java rules) from the network.
- cmdFlags = append(cmdFlags, "--experimental_repository_disable_download")
+ // This should be parameterized on the host OS, but let's restrict to linux
+ // to keep things simple for now.
+ fmt.Sprintf("--host_platform=%s", "//build/bazel/platforms:linux_x86_64"),
+
+ // Explicitly disable downloading rules (such as canonical C++ and Java rules) from the network.
+ "--experimental_repository_disable_download",
+
+ // Suppress noise
+ "--ui_event_filters=-INFO",
+ "--noshow_progress")
cmdFlags = append(cmdFlags, extraFlags...)
bazelCmd := exec.Command(paths.bazelPath, cmdFlags...)
@@ -682,8 +699,6 @@
func (context *bazelContext) InvokeBazel(config Config) error {
context.results = make(map[cqueryKey]string)
- var cqueryOutput string
- var cqueryErr string
var err error
soongInjectionPath := absolutePath(context.paths.injectedFilesDir())
@@ -700,45 +715,27 @@
return err
}
}
- err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "WORKSPACE.bazel"), []byte{}, 0666)
- if err != nil {
+ if err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "WORKSPACE.bazel"), []byte{}, 0666); err != nil {
return err
}
-
- err = ioutil.WriteFile(
- filepath.Join(mixedBuildsPath, "main.bzl"),
- context.mainBzlFileContents(), 0666)
- if err != nil {
+ if err = ioutil.WriteFile(filepath.Join(mixedBuildsPath, "main.bzl"), context.mainBzlFileContents(), 0666); err != nil {
return err
}
-
- err = ioutil.WriteFile(
- filepath.Join(mixedBuildsPath, "BUILD.bazel"),
- context.mainBuildFileContents(), 0666)
- if err != nil {
+ if err = ioutil.WriteFile(filepath.Join(mixedBuildsPath, "BUILD.bazel"), context.mainBuildFileContents(), 0666); err != nil {
return err
}
cqueryFileRelpath := filepath.Join(context.paths.injectedFilesDir(), "buildroot.cquery")
- err = ioutil.WriteFile(
- absolutePath(cqueryFileRelpath),
- context.cqueryStarlarkFileContents(), 0666)
- if err != nil {
+ if err = ioutil.WriteFile(absolutePath(cqueryFileRelpath), context.cqueryStarlarkFileContents(), 0666); err != nil {
return err
}
- buildrootLabel := "@soong_injection//mixed_builds:buildroot"
- cqueryOutput, cqueryErr, err = context.issueBazelCommand(
- context.paths,
- bazel.CqueryBuildRootRunName,
- bazelCommand{"cquery", fmt.Sprintf("deps(%s, 2)", buildrootLabel)},
- "--output=starlark",
- "--starlark:file="+absolutePath(cqueryFileRelpath))
- err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"),
- []byte(cqueryOutput), 0666)
+ const buildrootLabel = "@soong_injection//mixed_builds:buildroot"
+ cqueryCmd := bazelCommand{"cquery", fmt.Sprintf("deps(%s, 2)", buildrootLabel)}
+ cqueryOutput, cqueryErr, err := context.issueBazelCommand(context.paths, bazel.CqueryBuildRootRunName, cqueryCmd,
+ "--output=starlark", "--starlark:file="+absolutePath(cqueryFileRelpath))
if err != nil {
- return err
+ err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"), []byte(cqueryOutput), 0666)
}
-
if err != nil {
return err
}
@@ -750,7 +747,6 @@
cqueryResults[splitLine[0]] = splitLine[1]
}
}
-
for val := range context.requests {
if cqueryResult, ok := cqueryResults[getCqueryId(val)]; ok {
context.results[val] = cqueryResult
@@ -762,37 +758,27 @@
// Issue an aquery command to retrieve action information about the bazel build tree.
//
- var aqueryOutput string
- var coverageFlags []string
+ // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
+ // proto sources, which would add a number of unnecessary dependencies.
+ extraFlags := []string{"--output=jsonproto", "--include_file_write_contents"}
if Bool(config.productVariables.ClangCoverage) {
- coverageFlags = append(coverageFlags, "--collect_code_coverage")
- if len(config.productVariables.NativeCoveragePaths) > 0 ||
- len(config.productVariables.NativeCoverageExcludePaths) > 0 {
- includePaths := JoinWithPrefixAndSeparator(config.productVariables.NativeCoveragePaths, "+", ",")
- excludePaths := JoinWithPrefixAndSeparator(config.productVariables.NativeCoverageExcludePaths, "-", ",")
- if len(includePaths) > 0 && len(excludePaths) > 0 {
- includePaths += ","
- }
- coverageFlags = append(coverageFlags, fmt.Sprintf(`--instrumentation_filter=%s`,
- includePaths+excludePaths))
+ extraFlags = append(extraFlags, "--collect_code_coverage")
+ paths := make([]string, 0, 2)
+ if p := config.productVariables.NativeCoveragePaths; len(p) > 0 {
+ paths = append(paths, JoinWithPrefixAndSeparator(p, "+", ","))
+ }
+ if p := config.productVariables.NativeCoverageExcludePaths; len(p) > 0 {
+ paths = append(paths, JoinWithPrefixAndSeparator(p, "-", ","))
+ }
+ if len(paths) > 0 {
+ extraFlags = append(extraFlags, "--instrumentation_filter="+strings.Join(paths, ","))
}
}
-
- extraFlags := append([]string{"--output=jsonproto"}, coverageFlags...)
-
- aqueryOutput, _, err = context.issueBazelCommand(
- context.paths,
- bazel.AqueryBuildRootRunName,
- bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)},
- // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
- // proto sources, which would add a number of unnecessary dependencies.
- extraFlags...)
-
- if err != nil {
- return err
+ aqueryCmd := bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)}
+ if aqueryOutput, _, err := context.issueBazelCommand(context.paths, bazel.AqueryBuildRootRunName, aqueryCmd,
+ extraFlags...); err == nil {
+ context.buildStatements, context.depsets, err = bazel.AqueryBuildStatements([]byte(aqueryOutput))
}
-
- context.buildStatements, context.depsets, err = bazel.AqueryBuildStatements([]byte(aqueryOutput))
if err != nil {
return err
}
@@ -800,12 +786,8 @@
// 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.paths,
- bazel.BazelBuildPhonyRootRunName,
- bazelCommand{"build", "@soong_injection//mixed_builds:phonyroot"})
-
- if err != nil {
+ buildCmd := bazelCommand{"build", "@soong_injection//mixed_builds:phonyroot"}
+ if _, _, err = context.issueBazelCommand(context.paths, bazel.BazelBuildPhonyRootRunName, buildCmd); err != nil {
return err
}
@@ -874,19 +856,56 @@
executionRoot := path.Join(ctx.Config().BazelContext.OutputBase(), "execroot", "__main__")
bazelOutDir := path.Join(executionRoot, "bazel-out")
for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
- if len(buildStatement.Command) < 1 {
+ if len(buildStatement.Command) > 0 {
+ rule := NewRuleBuilder(pctx, ctx)
+ createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx)
+ desc := fmt.Sprintf("%s: %s", buildStatement.Mnemonic, buildStatement.OutputPaths)
+ rule.Build(fmt.Sprintf("bazel %d", index), desc)
+ continue
+ }
+ // Certain actions returned by aquery (for instance FileWrite) do not contain a command
+ // and thus require special treatment. If BuildStatement were an interface implementing
+ // buildRule(ctx) function, the code here would just call it.
+ // Unfortunately, the BuildStatement is defined in
+ // the 'bazel' package, which cannot depend on 'android' package where ctx is defined,
+ // because this would cause circular dependency. So, until we move aquery processing
+ // to the 'android' package, we need to handle special cases here.
+ if buildStatement.Mnemonic == "FileWrite" || buildStatement.Mnemonic == "SourceSymlinkManifest" {
+ // Pass file contents as the value of the rule's "content" argument.
+ // Escape newlines and $ in the contents (the action "writeBazelFile" restores "\\n"
+ // back to the newline, and Ninja reads $$ as $.
+ escaped := strings.ReplaceAll(strings.ReplaceAll(buildStatement.FileContents, "\n", "\\n"),
+ "$", "$$")
+ ctx.Build(pctx, BuildParams{
+ Rule: writeBazelFile,
+ Output: PathForBazelOut(ctx, buildStatement.OutputPaths[0]),
+ Description: fmt.Sprintf("%s %s", buildStatement.Mnemonic, buildStatement.OutputPaths[0]),
+ Args: map[string]string{
+ "content": escaped,
+ },
+ })
+ } else if buildStatement.Mnemonic == "SymlinkTree" {
+ // build-runfiles arguments are the manifest file and the target directory
+ // where it creates the symlink tree according to this manifest (and then
+ // writes the MANIFEST file to it).
+ outManifest := PathForBazelOut(ctx, buildStatement.OutputPaths[0])
+ outManifestPath := outManifest.String()
+ if !strings.HasSuffix(outManifestPath, "MANIFEST") {
+ panic("the base name of the symlink tree action should be MANIFEST, got " + outManifestPath)
+ }
+ outDir := filepath.Dir(outManifestPath)
+ ctx.Build(pctx, BuildParams{
+ Rule: buildRunfilesRule,
+ Output: outManifest,
+ Inputs: []Path{PathForBazelOut(ctx, buildStatement.InputPaths[0])},
+ Description: "symlink tree for " + outDir,
+ Args: map[string]string{
+ "outDir": outDir,
+ },
+ })
+ } else {
panic(fmt.Sprintf("unhandled build statement: %v", buildStatement))
}
- rule := NewRuleBuilder(pctx, ctx)
- createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx)
- // This is required to silence warnings pertaining to unexpected timestamps. Particularly,
- // some Bazel builtins (such as files in the bazel_tools directory) have far-future
- // timestamps. Without restat, Ninja would emit warnings that the input files of a
- // build statement have later timestamps than the outputs.
- rule.Restat()
-
- desc := fmt.Sprintf("%s: %s", buildStatement.Mnemonic, buildStatement.OutputPaths)
- rule.Build(fmt.Sprintf("bazel %d", index), desc)
}
}
@@ -899,7 +918,7 @@
if len(buildStatement.OutputPaths) > 0 {
cmd.Text("rm -f")
for _, outputPath := range buildStatement.OutputPaths {
- cmd.Text(outputPath)
+ cmd.Text(fmt.Sprintf("'%s'", outputPath))
}
cmd.Text("&&")
}
@@ -949,8 +968,15 @@
func getConfigString(key cqueryKey) string {
arch := key.configKey.arch
if len(arch) == 0 || arch == "common" {
- // Use host platform, which is currently hardcoded to be x86_64.
- arch = "x86_64"
+ if key.configKey.osType.Class == Device {
+ // For the generic Android, the expected result is "target|android", which
+ // corresponds to the product_variable_config named "android_target" in
+ // build/bazel/platforms/BUILD.bazel.
+ arch = "target"
+ } else {
+ // Use host platform, which is currently hardcoded to be x86_64.
+ arch = "x86_64"
+ }
}
osName := key.configKey.osType.Name
if len(osName) == 0 || osName == "common_os" || osName == "linux_glibc" {
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index 935ce4e..ec2541b 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -65,13 +65,9 @@
var testCases = []testCase{
{`
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -81,28 +77,18 @@
"outputIds": [1],
"primaryOutputId": 1
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 2]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "two"
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 2] }],
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "two" }]
}`,
- "cd 'er' && rm -f one && touch foo",
+ "cd 'test/exec_root' && rm -f 'one' && touch foo",
}, {`
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 10
- }, {
- "id": 2,
- "pathFragmentId": 20
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 10 },
+ { "id": 2, "pathFragmentId": 20 }],
"actions": [{
"targetId": 100,
"actionKey": "x",
@@ -111,41 +97,33 @@
"outputIds": [1, 2],
"primaryOutputId": 1
}],
- "pathFragments": [{
- "id": 10,
- "label": "one",
- "parentId": 30
- }, {
- "id": 20,
- "label": "one.d",
- "parentId": 30
- }, {
- "id": 30,
- "label": "parent"
- }]
+ "pathFragments": [
+ { "id": 10, "label": "one", "parentId": 30 },
+ { "id": 20, "label": "one.d", "parentId": 30 },
+ { "id": 30, "label": "parent" }]
}`,
- `cd 'er' && rm -f parent/one && bogus command && sed -i'' -E 's@(^|\s|")bazel-out/@\1bo/@g' 'parent/one.d'`,
+ `cd 'test/exec_root' && rm -f 'parent/one' && bogus command && sed -i'' -E 's@(^|\s|")bazel-out/@\1test/bazel_out/@g' 'parent/one.d'`,
},
}
- for _, testCase := range testCases {
+ for i, testCase := range testCases {
bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: testCase.input})
err := bazelContext.InvokeBazel(testConfig)
if err != nil {
- t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
+ t.Fatalf("testCase #%d: did not expect error invoking Bazel, but got %s", i+1, err)
}
got := bazelContext.BuildStatementsToRegister()
if want := 1; len(got) != want {
- t.Errorf("expected %d registered build statements, but got %#v", want, got)
+ t.Fatalf("expected %d registered build statements, but got %#v", want, got)
}
cmd := RuleBuilderCommand{}
- createCommand(&cmd, got[0], "er", "bo", PathContextForTesting(TestConfig("out", nil, "", nil)))
- if actual := cmd.buf.String(); testCase.command != actual {
- t.Errorf("expected: [%s], actual: [%s]", testCase.command, actual)
+ createCommand(&cmd, got[0], "test/exec_root", "test/bazel_out", PathContextForTesting(TestConfig("out", nil, "", nil)))
+ if actual, expected := cmd.buf.String(), testCase.command; expected != actual {
+ t.Errorf("expected: [%s], actual: [%s]", expected, actual)
}
}
}
diff --git a/android/config.go b/android/config.go
index cd902cb..47346fc 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1697,6 +1697,10 @@
return InList(name, c.config.productVariables.BuildBrokenInputDirModules)
}
+func (c *deviceConfig) BuildBrokenDepfile() bool {
+ return Bool(c.config.productVariables.BuildBrokenDepfile)
+}
+
func (c *deviceConfig) RequiresInsecureExecmemForSwiftshader() bool {
return c.config.productVariables.RequiresInsecureExecmemForSwiftshader
}
diff --git a/android/defaults.go b/android/defaults.go
index 8b121f6..54f44bc 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -15,6 +15,8 @@
package android
import (
+ "bytes"
+ "fmt"
"reflect"
"github.com/google/blueprint"
@@ -67,9 +69,11 @@
// Set the property structures into which defaults will be added.
setProperties(props []interface{}, variableProperties interface{})
- // Apply defaults from the supplied Defaults to the property structures supplied to
+ // Apply defaults from the supplied DefaultsModule to the property structures supplied to
// setProperties(...).
- applyDefaults(TopDownMutatorContext, []Defaults)
+ applyDefaults(TopDownMutatorContext, []DefaultsModule)
+
+ applySingleDefaultsWithTracker(EarlyModuleContext, DefaultsModule, defaultsTrackerFunc)
// Set the hook to be called after any defaults have been applied.
//
@@ -115,9 +119,23 @@
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().
@@ -151,6 +169,18 @@
// 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{}
@@ -167,6 +197,18 @@
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
}
@@ -190,6 +232,10 @@
&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)
@@ -218,6 +264,57 @@
// 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)
@@ -269,35 +366,204 @@
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 []Defaults) {
+ 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
+ }
+ }
for _, defaults := range defaultsList {
if ctx.Config().runningAsBp2Build {
applyNamespacedVariableDefaults(defaults, ctx)
}
- for _, prop := range defaultable.defaultableProperties {
- if prop == defaultable.defaultableVariableProperties {
- defaultable.applyDefaultVariableProperties(ctx, defaults, prop)
- } else {
- defaultable.applyDefaultProperties(ctx, defaults, prop)
+
+ 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))
+ } 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)
+ }
+ }
+ }
+}
+
+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(ctx TopDownMutatorContext,
- defaults Defaults, defaultableProp interface{}) {
+func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(defaults DefaultsModule,
+ defaultableProp interface{}, tracker defaultsTrackerFunc) error {
if defaultableProp == nil {
- return
+ return nil
}
defaultsProp := defaults.productVariableProperties()
if defaultsProp == nil {
- return
+ return nil
}
dst := []interface{}{
@@ -307,31 +573,26 @@
proptools.CloneEmptyProperties(reflect.ValueOf(defaultsProp)).Interface(),
}
- 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)
- }
- }
+ filter := filterForTracker(defaults, tracker)
+
+ return proptools.PrependMatchingProperties(dst, defaultsProp, filter)
}
-func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext,
- defaults Defaults, defaultableProp interface{}) {
+func (defaultable *DefaultableModuleBase) applyDefaultProperties(defaults DefaultsModule,
+ defaultableProp interface{}, checker defaultsTrackerFunc) error {
+
+ filter := filterForTracker(defaults, checker)
for _, def := range defaults.properties() {
if proptools.TypeEqual(defaultableProp, def) {
- err := proptools.PrependProperties(defaultableProp, def, nil)
+ err := proptools.PrependProperties(defaultableProp, def, filter)
if err != nil {
- if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
- ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
- } else {
- panic(err)
- }
+ return err
}
}
}
+
+ return nil
}
func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) {
@@ -348,12 +609,12 @@
func defaultsMutator(ctx TopDownMutatorContext) {
if defaultable, ok := ctx.Module().(Defaultable); ok {
if len(defaultable.defaults().Defaults) > 0 {
- var defaultsList []Defaults
+ var defaultsList []DefaultsModule
seen := make(map[Defaults]bool)
ctx.WalkDeps(func(module, parent Module) bool {
if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
- if defaults, ok := module.(Defaults); ok {
+ if defaults, ok := module.(DefaultsModule); ok {
if !seen[defaults] {
seen[defaults] = true
defaultsList = append(defaultsList, defaults)
diff --git a/android/defaults_test.go b/android/defaults_test.go
index a7542ab..d80f40c 100644
--- a/android/defaults_test.go
+++ b/android/defaults_test.go
@@ -19,7 +19,14 @@
)
type defaultsTestProperties struct {
- Foo []string
+ Foo []string
+ Bar []string
+ Nested struct {
+ Fizz *bool
+ }
+ Other struct {
+ Buzz *string
+ }
}
type defaultsTestModule struct {
@@ -130,3 +137,167 @@
// 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/sdk.go b/android/sdk.go
index 2dc0bd7..07b94b2 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -661,6 +661,10 @@
// an Android.bp file.
RequiresBpProperty() bool
+ // SupportedBuildReleases returns the string representation of a set of target build releases that
+ // support this member type.
+ SupportedBuildReleases() string
+
// UsableWithSdkAndSdkSnapshot returns true if the member type supports the sdk/sdk_snapshot,
// false otherwise.
UsableWithSdkAndSdkSnapshot() bool
@@ -673,6 +677,10 @@
// SupportedLinkages returns the names of the linkage variants supported by this module.
SupportedLinkages() []string
+ // ArePrebuiltsRequired returns true if prebuilts are required in the sdk snapshot, false
+ // otherwise.
+ ArePrebuiltsRequired() bool
+
// AddDependencies adds dependencies from the SDK module to all the module variants the member
// type contributes to the SDK. `names` is the list of module names given in the member type
// property (as returned by SdkPropertyName()) in the SDK module. The exact set of variants
@@ -773,7 +781,17 @@
// property to be specifiable in an Android.bp file.
BpPropertyNotRequired bool
- SupportsSdk bool
+ // The name of the first targeted build release.
+ //
+ // If not specified then it is assumed to be available on all targeted build releases.
+ SupportedBuildReleaseSpecification string
+
+ // Set to true if this must be usable with the sdk/sdk_snapshot module types. Otherwise, it will
+ // only be usable with module_exports/module_exports_snapshots module types.
+ SupportsSdk bool
+
+ // Set to true if prebuilt host artifacts of this member may be specific to the host OS. Only
+ // applicable to modules where HostSupported() is true.
HostOsDependent bool
// When set to true UseSourceModuleTypeInSnapshot indicates that the member type creates a source
@@ -781,6 +799,11 @@
// code from automatically adding a prefer: true flag.
UseSourceModuleTypeInSnapshot bool
+ // Set to proptools.BoolPtr(false) if this member does not generate prebuilts but is only provided
+ // to allow the sdk to gather members from this member's dependencies. If not specified then
+ // defaults to true.
+ PrebuiltsRequired *bool
+
// The list of supported traits.
Traits []SdkMemberTrait
}
@@ -793,6 +816,10 @@
return !b.BpPropertyNotRequired
}
+func (b *SdkMemberTypeBase) SupportedBuildReleases() string {
+ return b.SupportedBuildReleaseSpecification
+}
+
func (b *SdkMemberTypeBase) UsableWithSdkAndSdkSnapshot() bool {
return b.SupportsSdk
}
@@ -801,6 +828,10 @@
return b.HostOsDependent
}
+func (b *SdkMemberTypeBase) ArePrebuiltsRequired() bool {
+ return proptools.BoolDefault(b.PrebuiltsRequired, true)
+}
+
func (b *SdkMemberTypeBase) UsesSourceModuleTypeInSnapshot() bool {
return b.UseSourceModuleTypeInSnapshot
}
diff --git a/android/variable.go b/android/variable.go
index 734ed1b..50fc304 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -429,6 +429,7 @@
ShippingApiLevel *string `json:",omitempty"`
+ BuildBrokenDepfile *bool `json:",omitempty"`
BuildBrokenEnforceSyspropOwner bool `json:",omitempty"`
BuildBrokenTrebleSyspropNeverallow bool `json:",omitempty"`
BuildBrokenVendorPropertyNamespace bool `json:",omitempty"`
diff --git a/apex/Android.bp b/apex/Android.bp
index fcdf8e6..6533c61 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -23,6 +23,7 @@
srcs: [
"androidmk.go",
"apex.go",
+ "apex_sdk_member.go",
"apex_singleton.go",
"builder.go",
"constants.go",
diff --git a/apex/apex.go b/apex/apex.go
index 7e913e8..7b6707c 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -606,6 +606,18 @@
// replacement. This is needed because some prebuilt modules do not provide all the information
// needed by the apex.
sourceOnly bool
+
+ // If not-nil and an APEX is a member of an SDK then dependencies of that APEX with this tag will
+ // also be added as exported members of that SDK.
+ memberType android.SdkMemberType
+}
+
+func (d *dependencyTag) SdkMemberType(_ android.Module) android.SdkMemberType {
+ return d.memberType
+}
+
+func (d *dependencyTag) ExportMember() bool {
+ return true
}
func (d *dependencyTag) String() string {
@@ -617,6 +629,7 @@
}
var _ android.ReplaceSourceWithPrebuilt = &dependencyTag{}
+var _ android.SdkMemberDependencyTag = &dependencyTag{}
var (
androidAppTag = &dependencyTag{name: "androidApp", payload: true}
@@ -624,8 +637,8 @@
certificateTag = &dependencyTag{name: "certificate"}
executableTag = &dependencyTag{name: "executable", payload: true}
fsTag = &dependencyTag{name: "filesystem", payload: true}
- bcpfTag = &dependencyTag{name: "bootclasspathFragment", payload: true, sourceOnly: true}
- sscpfTag = &dependencyTag{name: "systemserverclasspathFragment", payload: true, sourceOnly: true}
+ bcpfTag = &dependencyTag{name: "bootclasspathFragment", payload: true, sourceOnly: true, memberType: java.BootclasspathFragmentSdkMemberType}
+ sscpfTag = &dependencyTag{name: "systemserverclasspathFragment", payload: true, sourceOnly: true, memberType: java.SystemServerClasspathFragmentSdkMemberType}
compatConfigTag = &dependencyTag{name: "compatConfig", payload: true, sourceOnly: true}
javaLibTag = &dependencyTag{name: "javaLib", payload: true}
jniLibTag = &dependencyTag{name: "jniLib", payload: true}
@@ -1338,7 +1351,7 @@
var _ android.DepIsInSameApex = (*apexBundle)(nil)
// Implements android.DepInInSameApex
-func (a *apexBundle) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+func (a *apexBundle) DepIsInSameApex(_ android.BaseModuleContext, _ android.Module) bool {
// direct deps of an APEX bundle are all part of the APEX bundle
// TODO(jiyong): shouldn't we look into the payload field of the dependencyTag?
return true
@@ -1474,7 +1487,7 @@
}
// Then follow the global setting
- globalSanitizerNames := []string{}
+ var globalSanitizerNames []string
if a.Host() {
globalSanitizerNames = config.SanitizeHost()
} else {
@@ -1790,6 +1803,382 @@
}
}
+type visitorContext struct {
+ // all the files that will be included in this APEX
+ filesInfo []apexFile
+
+ // native lib dependencies
+ provideNativeLibs []string
+ requireNativeLibs []string
+
+ handleSpecialLibs bool
+}
+
+func (vctx *visitorContext) normalizeFileInfo() {
+ encountered := make(map[string]apexFile)
+ for _, f := range vctx.filesInfo {
+ dest := filepath.Join(f.installDir, f.builtFile.Base())
+ if e, ok := encountered[dest]; !ok {
+ encountered[dest] = f
+ } else {
+ // If a module is directly included and also transitively depended on
+ // consider it as directly included.
+ e.transitiveDep = e.transitiveDep && f.transitiveDep
+ encountered[dest] = e
+ }
+ }
+ vctx.filesInfo = vctx.filesInfo[:0]
+ for _, v := range encountered {
+ vctx.filesInfo = append(vctx.filesInfo, v)
+ }
+ sort.Slice(vctx.filesInfo, func(i, j int) bool {
+ // Sort by destination path so as to ensure consistent ordering even if the source of the files
+ // changes.
+ return vctx.filesInfo[i].path() < vctx.filesInfo[j].path()
+ })
+}
+
+func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, child, parent blueprint.Module) bool {
+ depTag := ctx.OtherModuleDependencyTag(child)
+ if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
+ return false
+ }
+ if mod, ok := child.(android.Module); ok && !mod.Enabled() {
+ return false
+ }
+ depName := ctx.OtherModuleName(child)
+ if _, isDirectDep := parent.(*apexBundle); isDirectDep {
+ switch depTag {
+ case sharedLibTag, jniLibTag:
+ isJniLib := depTag == jniLibTag
+ switch ch := child.(type) {
+ case *cc.Module:
+ fi := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
+ fi.isJniLib = isJniLib
+ vctx.filesInfo = append(vctx.filesInfo, fi)
+ // Collect the list of stub-providing libs except:
+ // - VNDK libs are only for vendors
+ // - bootstrap bionic libs are treated as provided by system
+ if ch.HasStubsVariants() && !a.vndkApex && !cc.InstallToBootstrap(ch.BaseModuleName(), ctx.Config()) {
+ vctx.provideNativeLibs = append(vctx.provideNativeLibs, fi.stem())
+ }
+ return true // track transitive dependencies
+ case *rust.Module:
+ fi := apexFileForRustLibrary(ctx, ch)
+ fi.isJniLib = isJniLib
+ vctx.filesInfo = append(vctx.filesInfo, fi)
+ return true // track transitive dependencies
+ default:
+ propertyName := "native_shared_libs"
+ if isJniLib {
+ propertyName = "jni_libs"
+ }
+ ctx.PropertyErrorf(propertyName, "%q is not a cc_library or cc_library_shared module", depName)
+ }
+ case executableTag:
+ switch ch := child.(type) {
+ case *cc.Module:
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForExecutable(ctx, ch))
+ return true // track transitive dependencies
+ case *python.Module:
+ if ch.HostToolPath().Valid() {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForPyBinary(ctx, ch))
+ }
+ case bootstrap.GoBinaryTool:
+ if a.Host() {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForGoBinary(ctx, depName, ch))
+ }
+ case *rust.Module:
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForRustExecutable(ctx, ch))
+ return true // track transitive dependencies
+ default:
+ ctx.PropertyErrorf("binaries",
+ "%q is neither cc_binary, rust_binary, (embedded) py_binary, (host) blueprint_go_binary, nor (host) bootstrap_go_binary", depName)
+ }
+ case shBinaryTag:
+ if csh, ok := child.(*sh.ShBinary); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForShBinary(ctx, csh))
+ } else {
+ ctx.PropertyErrorf("sh_binaries", "%q is not a sh_binary module", depName)
+ }
+ case bcpfTag:
+ bcpfModule, ok := child.(*java.BootclasspathFragmentModule)
+ if !ok {
+ ctx.PropertyErrorf("bootclasspath_fragments", "%q is not a bootclasspath_fragment module", depName)
+ return false
+ }
+
+ vctx.filesInfo = append(vctx.filesInfo, apexBootclasspathFragmentFiles(ctx, child)...)
+ for _, makeModuleName := range bcpfModule.BootImageDeviceInstallMakeModules() {
+ a.requiredDeps = append(a.requiredDeps, makeModuleName)
+ }
+ return true
+ case sscpfTag:
+ if _, ok := child.(*java.SystemServerClasspathModule); !ok {
+ ctx.PropertyErrorf("systemserverclasspath_fragments",
+ "%q is not a systemserverclasspath_fragment module", depName)
+ return false
+ }
+ if af := apexClasspathFragmentProtoFile(ctx, child); af != nil {
+ vctx.filesInfo = append(vctx.filesInfo, *af)
+ }
+ return true
+ case javaLibTag:
+ switch child.(type) {
+ case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport, *java.Import:
+ af := apexFileForJavaModule(ctx, child.(javaModule))
+ if !af.ok() {
+ ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
+ return false
+ }
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ default:
+ ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
+ }
+ case androidAppTag:
+ switch ap := child.(type) {
+ case *java.AndroidApp:
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForAndroidApp(ctx, ap))
+ return true // track transitive dependencies
+ case *java.AndroidAppImport:
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForAndroidApp(ctx, ap))
+ case *java.AndroidTestHelperApp:
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForAndroidApp(ctx, ap))
+ case *java.AndroidAppSet:
+ appDir := "app"
+ if ap.Privileged() {
+ appDir = "priv-app"
+ }
+ // TODO(b/224589412, b/226559955): Ensure that the dirname is
+ // suffixed so that PackageManager correctly invalidates the
+ // existing installed apk in favour of the new APK-in-APEX.
+ // See bugs for more information.
+ appDirName := filepath.Join(appDir, ap.BaseModuleName()+"@"+sanitizedBuildIdForPath(ctx))
+ af := newApexFile(ctx, ap.OutputFile(), ap.BaseModuleName(), appDirName, appSet, ap)
+ af.certificate = java.PresignedCertificate
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ default:
+ ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
+ }
+ case rroTag:
+ if rro, ok := child.(java.RuntimeResourceOverlayModule); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForRuntimeResourceOverlay(ctx, rro))
+ } else {
+ ctx.PropertyErrorf("rros", "%q is not an runtime_resource_overlay module", depName)
+ }
+ case bpfTag:
+ if bpfProgram, ok := child.(bpf.BpfModule); ok {
+ filesToCopy, _ := bpfProgram.OutputFiles("")
+ apex_sub_dir := bpfProgram.SubDir()
+ for _, bpfFile := range filesToCopy {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForBpfProgram(ctx, bpfFile, apex_sub_dir, bpfProgram))
+ }
+ } else {
+ ctx.PropertyErrorf("bpfs", "%q is not a bpf module", depName)
+ }
+ case fsTag:
+ if fs, ok := child.(filesystem.Filesystem); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForFilesystem(ctx, fs.OutputPath(), fs))
+ } else {
+ ctx.PropertyErrorf("filesystems", "%q is not a filesystem module", depName)
+ }
+ case prebuiltTag:
+ if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+ } else {
+ ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
+ }
+ case compatConfigTag:
+ if compatConfig, ok := child.(java.PlatformCompatConfigIntf); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForCompatConfig(ctx, compatConfig, depName))
+ } else {
+ ctx.PropertyErrorf("compat_configs", "%q is not a platform_compat_config module", depName)
+ }
+ case testTag:
+ if ccTest, ok := child.(*cc.Module); ok {
+ if ccTest.IsTestPerSrcAllTestsVariation() {
+ // Multiple-output test module (where `test_per_src: true`).
+ //
+ // `ccTest` is the "" ("all tests") variation of a `test_per_src` module.
+ // We do not add this variation to `filesInfo`, as it has no output;
+ // however, we do add the other variations of this module as indirect
+ // dependencies (see below).
+ } else {
+ // Single-output test module (where `test_per_src: false`).
+ af := apexFileForExecutable(ctx, ccTest)
+ af.class = nativeTest
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ }
+ return true // track transitive dependencies
+ } else {
+ ctx.PropertyErrorf("tests", "%q is not a cc module", depName)
+ }
+ case keyTag:
+ if key, ok := child.(*apexKey); ok {
+ a.privateKeyFile = key.privateKeyFile
+ a.publicKeyFile = key.publicKeyFile
+ } else {
+ ctx.PropertyErrorf("key", "%q is not an apex_key module", depName)
+ }
+ case certificateTag:
+ if dep, ok := child.(*java.AndroidAppCertificate); ok {
+ a.containerCertificateFile = dep.Certificate.Pem
+ a.containerPrivateKeyFile = dep.Certificate.Key
+ } else {
+ ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", depName)
+ }
+ case android.PrebuiltDepTag:
+ // If the prebuilt is force disabled, remember to delete the prebuilt file
+ // that might have been installed in the previous builds
+ if prebuilt, ok := child.(prebuilt); ok && prebuilt.isForceDisabled() {
+ a.prebuiltFileToDelete = prebuilt.InstallFilename()
+ }
+ }
+ return false
+ }
+
+ if a.vndkApex {
+ return false
+ }
+
+ // indirect dependencies
+ am, ok := child.(android.ApexModule)
+ if !ok {
+ return false
+ }
+ // We cannot use a switch statement on `depTag` here as the checked
+ // tags used below are private (e.g. `cc.sharedDepTag`).
+ if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) {
+ if ch, ok := child.(*cc.Module); ok {
+ if ch.UseVndk() && proptools.Bool(a.properties.Use_vndk_as_stable) && ch.IsVndk() {
+ vctx.requireNativeLibs = append(vctx.requireNativeLibs, ":vndk")
+ return false
+ }
+ af := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
+ af.transitiveDep = true
+
+ // Always track transitive dependencies for host.
+ if a.Host() {
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true
+ }
+
+ abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo)
+ if !abInfo.Contents.DirectlyInApex(depName) && (ch.IsStubs() || ch.HasStubsVariants()) {
+ // If the dependency is a stubs lib, don't include it in this APEX,
+ // but make sure that the lib is installed on the device.
+ // In case no APEX is having the lib, the lib is installed to the system
+ // partition.
+ //
+ // Always include if we are a host-apex however since those won't have any
+ // system libraries.
+ if !am.DirectlyInAnyApex() {
+ // we need a module name for Make
+ name := ch.ImplementationModuleNameForMake(ctx) + ch.Properties.SubName
+ if !android.InList(name, a.requiredDeps) {
+ a.requiredDeps = append(a.requiredDeps, name)
+ }
+ }
+ vctx.requireNativeLibs = append(vctx.requireNativeLibs, af.stem())
+ // Don't track further
+ return false
+ }
+
+ // If the dep is not considered to be in the same
+ // apex, don't add it to filesInfo so that it is not
+ // included in this APEX.
+ // TODO(jiyong): move this to at the top of the
+ // else-if clause for the indirect dependencies.
+ // Currently, that's impossible because we would
+ // like to record requiredNativeLibs even when
+ // DepIsInSameAPex is false. We also shouldn't do
+ // this for host.
+ //
+ // TODO(jiyong): explain why the same module is passed in twice.
+ // Switching the first am to parent breaks lots of tests.
+ if !android.IsDepInSameApex(ctx, am, am) {
+ return false
+ }
+
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ } else if rm, ok := child.(*rust.Module); ok {
+ af := apexFileForRustLibrary(ctx, rm)
+ af.transitiveDep = true
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ }
+ } else if cc.IsTestPerSrcDepTag(depTag) {
+ if ch, ok := child.(*cc.Module); ok {
+ af := apexFileForExecutable(ctx, ch)
+ // Handle modules created as `test_per_src` variations of a single test module:
+ // use the name of the generated test binary (`fileToCopy`) instead of the name
+ // of the original test module (`depName`, shared by all `test_per_src`
+ // variations of that module).
+ af.androidMkModuleName = filepath.Base(af.builtFile.String())
+ // these are not considered transitive dep
+ af.transitiveDep = false
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ }
+ } else if cc.IsHeaderDepTag(depTag) {
+ // nothing
+ } else if java.IsJniDepTag(depTag) {
+ // Because APK-in-APEX embeds jni_libs transitively, we don't need to track transitive deps
+ } else if java.IsXmlPermissionsFileDepTag(depTag) {
+ if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+ }
+ } else if rust.IsDylibDepTag(depTag) {
+ if rustm, ok := child.(*rust.Module); ok && rustm.IsInstallableToApex() {
+ af := apexFileForRustLibrary(ctx, rustm)
+ af.transitiveDep = true
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ }
+ } else if rust.IsRlibDepTag(depTag) {
+ // Rlib is statically linked, but it might have shared lib
+ // dependencies. Track them.
+ return true
+ } else if java.IsBootclasspathFragmentContentDepTag(depTag) {
+ // Add the contents of the bootclasspath fragment to the apex.
+ switch child.(type) {
+ case *java.Library, *java.SdkLibrary:
+ javaModule := child.(javaModule)
+ af := apexFileForBootclasspathFragmentContentModule(ctx, parent, javaModule)
+ if !af.ok() {
+ ctx.PropertyErrorf("bootclasspath_fragments",
+ "bootclasspath_fragment content %q is not configured to be compiled into dex", depName)
+ return false
+ }
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ default:
+ ctx.PropertyErrorf("bootclasspath_fragments",
+ "bootclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
+ }
+ } else if java.IsSystemServerClasspathFragmentContentDepTag(depTag) {
+ // Add the contents of the systemserverclasspath fragment to the apex.
+ switch child.(type) {
+ case *java.Library, *java.SdkLibrary:
+ af := apexFileForJavaModule(ctx, child.(javaModule))
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ default:
+ ctx.PropertyErrorf("systemserverclasspath_fragments",
+ "systemserverclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
+ }
+ } else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok {
+ // nothing
+ } else if depTag == android.DarwinUniversalVariantTag {
+ // nothing
+ } else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
+ ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
+ }
+ return false
+}
+
// Creates build rules for an APEX. It consists of the following major steps:
//
// 1) do some validity checks such as apex_available, min_sdk_version, etc.
@@ -1812,386 +2201,23 @@
////////////////////////////////////////////////////////////////////////////////////////////
// 2) traverse the dependency tree to collect apexFile structs from them.
- // all the files that will be included in this APEX
- var filesInfo []apexFile
-
- // native lib dependencies
- var provideNativeLibs []string
- var requireNativeLibs []string
-
- handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
-
// Collect the module directory for IDE info in java/jdeps.go.
a.modulePaths = append(a.modulePaths, ctx.ModuleDir())
// TODO(jiyong): do this using WalkPayloadDeps
// TODO(jiyong): make this clean!!!
- ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
- depTag := ctx.OtherModuleDependencyTag(child)
- if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
- return false
- }
- if mod, ok := child.(android.Module); ok && !mod.Enabled() {
- return false
- }
- depName := ctx.OtherModuleName(child)
- if _, isDirectDep := parent.(*apexBundle); isDirectDep {
- switch depTag {
- case sharedLibTag, jniLibTag:
- isJniLib := depTag == jniLibTag
- if c, ok := child.(*cc.Module); ok {
- fi := apexFileForNativeLibrary(ctx, c, handleSpecialLibs)
- fi.isJniLib = isJniLib
- filesInfo = append(filesInfo, fi)
- // Collect the list of stub-providing libs except:
- // - VNDK libs are only for vendors
- // - bootstrap bionic libs are treated as provided by system
- if c.HasStubsVariants() && !a.vndkApex && !cc.InstallToBootstrap(c.BaseModuleName(), ctx.Config()) {
- provideNativeLibs = append(provideNativeLibs, fi.stem())
- }
- return true // track transitive dependencies
- } else if r, ok := child.(*rust.Module); ok {
- fi := apexFileForRustLibrary(ctx, r)
- fi.isJniLib = isJniLib
- filesInfo = append(filesInfo, fi)
- return true // track transitive dependencies
- } else {
- propertyName := "native_shared_libs"
- if isJniLib {
- propertyName = "jni_libs"
- }
- ctx.PropertyErrorf(propertyName, "%q is not a cc_library or cc_library_shared module", depName)
- }
- case executableTag:
- if cc, ok := child.(*cc.Module); ok {
- filesInfo = append(filesInfo, apexFileForExecutable(ctx, cc))
- return true // track transitive dependencies
- } else if py, ok := child.(*python.Module); ok && py.HostToolPath().Valid() {
- filesInfo = append(filesInfo, apexFileForPyBinary(ctx, py))
- } else if gb, ok := child.(bootstrap.GoBinaryTool); ok && a.Host() {
- filesInfo = append(filesInfo, apexFileForGoBinary(ctx, depName, gb))
- } else if rust, ok := child.(*rust.Module); ok {
- filesInfo = append(filesInfo, apexFileForRustExecutable(ctx, rust))
- return true // track transitive dependencies
- } else {
- ctx.PropertyErrorf("binaries", "%q is neither cc_binary, rust_binary, (embedded) py_binary, (host) blueprint_go_binary, nor (host) bootstrap_go_binary", depName)
- }
- case shBinaryTag:
- if sh, ok := child.(*sh.ShBinary); ok {
- filesInfo = append(filesInfo, apexFileForShBinary(ctx, sh))
- } else {
- ctx.PropertyErrorf("sh_binaries", "%q is not a sh_binary module", depName)
- }
- case bcpfTag:
- {
- bcpfModule, ok := child.(*java.BootclasspathFragmentModule)
- if !ok {
- ctx.PropertyErrorf("bootclasspath_fragments", "%q is not a bootclasspath_fragment module", depName)
- return false
- }
-
- filesToAdd := apexBootclasspathFragmentFiles(ctx, child)
- filesInfo = append(filesInfo, filesToAdd...)
- for _, makeModuleName := range bcpfModule.BootImageDeviceInstallMakeModules() {
- a.requiredDeps = append(a.requiredDeps, makeModuleName)
- }
- return true
- }
- case sscpfTag:
- {
- if _, ok := child.(*java.SystemServerClasspathModule); !ok {
- ctx.PropertyErrorf("systemserverclasspath_fragments", "%q is not a systemserverclasspath_fragment module", depName)
- return false
- }
- if af := apexClasspathFragmentProtoFile(ctx, child); af != nil {
- filesInfo = append(filesInfo, *af)
- }
- return true
- }
- case javaLibTag:
- switch child.(type) {
- case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport, *java.Import:
- af := apexFileForJavaModule(ctx, child.(javaModule))
- if !af.ok() {
- ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
- return false
- }
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- default:
- ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
- }
- case androidAppTag:
- if ap, ok := child.(*java.AndroidApp); ok {
- filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
- return true // track transitive dependencies
- } else if ap, ok := child.(*java.AndroidAppImport); ok {
- filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
- } else if ap, ok := child.(*java.AndroidTestHelperApp); ok {
- filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
- } else if ap, ok := child.(*java.AndroidAppSet); ok {
- appDir := "app"
- if ap.Privileged() {
- appDir = "priv-app"
- }
- // TODO(b/224589412, b/226559955): Ensure that the dirname is
- // suffixed so that PackageManager correctly invalidates the
- // existing installed apk in favour of the new APK-in-APEX.
- // See bugs for more information.
- appDirName := filepath.Join(appDir, ap.BaseModuleName()+"@"+sanitizedBuildIdForPath(ctx))
- af := newApexFile(ctx, ap.OutputFile(), ap.BaseModuleName(), appDirName, appSet, ap)
- af.certificate = java.PresignedCertificate
- filesInfo = append(filesInfo, af)
- } else {
- ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
- }
- case rroTag:
- if rro, ok := child.(java.RuntimeResourceOverlayModule); ok {
- filesInfo = append(filesInfo, apexFileForRuntimeResourceOverlay(ctx, rro))
- } else {
- ctx.PropertyErrorf("rros", "%q is not an runtime_resource_overlay module", depName)
- }
- case bpfTag:
- if bpfProgram, ok := child.(bpf.BpfModule); ok {
- filesToCopy, _ := bpfProgram.OutputFiles("")
- apex_sub_dir := bpfProgram.SubDir()
- for _, bpfFile := range filesToCopy {
- filesInfo = append(filesInfo, apexFileForBpfProgram(ctx, bpfFile, apex_sub_dir, bpfProgram))
- }
- } else {
- ctx.PropertyErrorf("bpfs", "%q is not a bpf module", depName)
- }
- case fsTag:
- if fs, ok := child.(filesystem.Filesystem); ok {
- filesInfo = append(filesInfo, apexFileForFilesystem(ctx, fs.OutputPath(), fs))
- } else {
- ctx.PropertyErrorf("filesystems", "%q is not a filesystem module", depName)
- }
- case prebuiltTag:
- if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
- filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
- } else {
- ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
- }
- case compatConfigTag:
- if compatConfig, ok := child.(java.PlatformCompatConfigIntf); ok {
- filesInfo = append(filesInfo, apexFileForCompatConfig(ctx, compatConfig, depName))
- } else {
- ctx.PropertyErrorf("compat_configs", "%q is not a platform_compat_config module", depName)
- }
- case testTag:
- if ccTest, ok := child.(*cc.Module); ok {
- if ccTest.IsTestPerSrcAllTestsVariation() {
- // Multiple-output test module (where `test_per_src: true`).
- //
- // `ccTest` is the "" ("all tests") variation of a `test_per_src` module.
- // We do not add this variation to `filesInfo`, as it has no output;
- // however, we do add the other variations of this module as indirect
- // dependencies (see below).
- } else {
- // Single-output test module (where `test_per_src: false`).
- af := apexFileForExecutable(ctx, ccTest)
- af.class = nativeTest
- filesInfo = append(filesInfo, af)
- }
- return true // track transitive dependencies
- } else {
- ctx.PropertyErrorf("tests", "%q is not a cc module", depName)
- }
- case keyTag:
- if key, ok := child.(*apexKey); ok {
- a.privateKeyFile = key.privateKeyFile
- a.publicKeyFile = key.publicKeyFile
- } else {
- ctx.PropertyErrorf("key", "%q is not an apex_key module", depName)
- }
- return false
- case certificateTag:
- if dep, ok := child.(*java.AndroidAppCertificate); ok {
- a.containerCertificateFile = dep.Certificate.Pem
- a.containerPrivateKeyFile = dep.Certificate.Key
- } else {
- ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", depName)
- }
- case android.PrebuiltDepTag:
- // If the prebuilt is force disabled, remember to delete the prebuilt file
- // that might have been installed in the previous builds
- if prebuilt, ok := child.(prebuilt); ok && prebuilt.isForceDisabled() {
- a.prebuiltFileToDelete = prebuilt.InstallFilename()
- }
- }
- } else if !a.vndkApex {
- // indirect dependencies
- if am, ok := child.(android.ApexModule); ok {
- // We cannot use a switch statement on `depTag` here as the checked
- // tags used below are private (e.g. `cc.sharedDepTag`).
- if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) {
- if cc, ok := child.(*cc.Module); ok {
- if cc.UseVndk() && proptools.Bool(a.properties.Use_vndk_as_stable) && cc.IsVndk() {
- requireNativeLibs = append(requireNativeLibs, ":vndk")
- return false
- }
- af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs)
- af.transitiveDep = true
-
- // Always track transitive dependencies for host.
- if a.Host() {
- filesInfo = append(filesInfo, af)
- return true
- }
-
- abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo)
- if !abInfo.Contents.DirectlyInApex(depName) && (cc.IsStubs() || cc.HasStubsVariants()) {
- // If the dependency is a stubs lib, don't include it in this APEX,
- // but make sure that the lib is installed on the device.
- // In case no APEX is having the lib, the lib is installed to the system
- // partition.
- //
- // Always include if we are a host-apex however since those won't have any
- // system libraries.
- if !am.DirectlyInAnyApex() {
- // we need a module name for Make
- name := cc.ImplementationModuleNameForMake(ctx) + cc.Properties.SubName
- if !android.InList(name, a.requiredDeps) {
- a.requiredDeps = append(a.requiredDeps, name)
- }
- }
- requireNativeLibs = append(requireNativeLibs, af.stem())
- // Don't track further
- return false
- }
-
- // If the dep is not considered to be in the same
- // apex, don't add it to filesInfo so that it is not
- // included in this APEX.
- // TODO(jiyong): move this to at the top of the
- // else-if clause for the indirect dependencies.
- // Currently, that's impossible because we would
- // like to record requiredNativeLibs even when
- // DepIsInSameAPex is false. We also shouldn't do
- // this for host.
- //
- // TODO(jiyong): explain why the same module is passed in twice.
- // Switching the first am to parent breaks lots of tests.
- if !android.IsDepInSameApex(ctx, am, am) {
- return false
- }
-
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- } else if rm, ok := child.(*rust.Module); ok {
- af := apexFileForRustLibrary(ctx, rm)
- af.transitiveDep = true
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- }
- } else if cc.IsTestPerSrcDepTag(depTag) {
- if cc, ok := child.(*cc.Module); ok {
- af := apexFileForExecutable(ctx, cc)
- // Handle modules created as `test_per_src` variations of a single test module:
- // use the name of the generated test binary (`fileToCopy`) instead of the name
- // of the original test module (`depName`, shared by all `test_per_src`
- // variations of that module).
- af.androidMkModuleName = filepath.Base(af.builtFile.String())
- // these are not considered transitive dep
- af.transitiveDep = false
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- }
- } else if cc.IsHeaderDepTag(depTag) {
- // nothing
- } else if java.IsJniDepTag(depTag) {
- // Because APK-in-APEX embeds jni_libs transitively, we don't need to track transitive deps
- return false
- } else if java.IsXmlPermissionsFileDepTag(depTag) {
- if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
- filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
- }
- } else if rust.IsDylibDepTag(depTag) {
- if rustm, ok := child.(*rust.Module); ok && rustm.IsInstallableToApex() {
- af := apexFileForRustLibrary(ctx, rustm)
- af.transitiveDep = true
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- }
- } else if rust.IsRlibDepTag(depTag) {
- // Rlib is statically linked, but it might have shared lib
- // dependencies. Track them.
- return true
- } else if java.IsBootclasspathFragmentContentDepTag(depTag) {
- // Add the contents of the bootclasspath fragment to the apex.
- switch child.(type) {
- case *java.Library, *java.SdkLibrary:
- javaModule := child.(javaModule)
- af := apexFileForBootclasspathFragmentContentModule(ctx, parent, javaModule)
- if !af.ok() {
- ctx.PropertyErrorf("bootclasspath_fragments", "bootclasspath_fragment content %q is not configured to be compiled into dex", depName)
- return false
- }
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- default:
- ctx.PropertyErrorf("bootclasspath_fragments", "bootclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
- }
- } else if java.IsSystemServerClasspathFragmentContentDepTag(depTag) {
- // Add the contents of the systemserverclasspath fragment to the apex.
- switch child.(type) {
- case *java.Library, *java.SdkLibrary:
- af := apexFileForJavaModule(ctx, child.(javaModule))
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- default:
- ctx.PropertyErrorf("systemserverclasspath_fragments", "systemserverclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
- }
- } else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok {
- // nothing
- } else if depTag == android.DarwinUniversalVariantTag {
- // nothing
- } else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
- ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
- }
- }
- }
- return false
- })
+ 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()
if a.privateKeyFile == nil {
ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.overridableProperties.Key))
return
}
- // Remove duplicates in filesInfo
- removeDup := func(filesInfo []apexFile) []apexFile {
- encountered := make(map[string]apexFile)
- for _, f := range filesInfo {
- dest := filepath.Join(f.installDir, f.builtFile.Base())
- if e, ok := encountered[dest]; !ok {
- encountered[dest] = f
- } else {
- // If a module is directly included and also transitively depended on
- // consider it as directly included.
- e.transitiveDep = e.transitiveDep && f.transitiveDep
- encountered[dest] = e
- }
- }
- var result []apexFile
- for _, v := range encountered {
- result = append(result, v)
- }
- return result
- }
- filesInfo = removeDup(filesInfo)
-
- // Sort to have consistent build rules
- sort.Slice(filesInfo, func(i, j int) bool {
- // Sort by destination path so as to ensure consistent ordering even if the source of the files
- // changes.
- return filesInfo[i].path() < filesInfo[j].path()
- })
-
////////////////////////////////////////////////////////////////////////////////////////////
// 3) some fields in apexBundle struct are configured
a.installDir = android.PathForModuleInstall(ctx, "apex")
- a.filesInfo = filesInfo
+ a.filesInfo = vctx.filesInfo
// Set suffix and primaryApexType depending on the ApexType
buildFlattenedAsDefault := ctx.Config().FlattenApex()
@@ -2267,7 +2293,7 @@
////////////////////////////////////////////////////////////////////////////////////////////
// 4) generate the build rules to create the APEX. This is done in builder.go.
- a.buildManifest(ctx, provideNativeLibs, requireNativeLibs)
+ a.buildManifest(ctx, vctx.provideNativeLibs, vctx.requireNativeLibs)
if a.properties.ApexType == flattenedApex {
a.buildFlattenedApex(ctx)
} else {
@@ -2458,7 +2484,7 @@
android.BazelModuleBase
}
-func (o *OverrideApex) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (o *OverrideApex) GenerateAndroidBuildActions(_ android.ModuleContext) {
// All the overrides happen in the base module.
}
diff --git a/apex/apex_sdk_member.go b/apex/apex_sdk_member.go
new file mode 100644
index 0000000..284158f
--- /dev/null
+++ b/apex/apex_sdk_member.go
@@ -0,0 +1,58 @@
+// Copyright (C) 2022 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 (
+ "android/soong/android"
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+// This file contains support for using apex modules within an sdk.
+
+func init() {
+ // Register sdk member types.
+ android.RegisterSdkMemberType(&apexSdkMemberType{
+ SdkMemberTypeBase: android.SdkMemberTypeBase{
+ PropertyName: "apexes",
+ SupportsSdk: true,
+
+ // The apexes property does not need to be included in the snapshot as adding an apex to an
+ // sdk does not produce any prebuilts of the apex.
+ PrebuiltsRequired: proptools.BoolPtr(false),
+ },
+ })
+}
+
+type apexSdkMemberType struct {
+ android.SdkMemberTypeBase
+}
+
+func (mt *apexSdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ ctx.AddVariationDependencies(nil, dependencyTag, names...)
+}
+
+func (mt *apexSdkMemberType) IsInstance(module android.Module) bool {
+ _, ok := module.(*apexBundle)
+ return ok
+}
+
+func (mt *apexSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ panic("Sdk does not create prebuilts of the apexes in its snapshot")
+}
+
+func (mt *apexSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ panic("Sdk does not create prebuilts of the apexes in its snapshot")
+}
diff --git a/apex/builder.go b/apex/builder.go
index fc9bb3b..e3c4476 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -82,6 +82,11 @@
Description: "prepare ${out}",
}, "provideNativeLibs", "requireNativeLibs", "opt")
+ stripCommentsApexManifestRule = pctx.StaticRule("stripCommentsApexManifestRule", blueprint.RuleParams{
+ Command: `sed '/^\s*\/\//d' $in > $out`,
+ Description: "strip lines starting with // ${in}=>${out}",
+ })
+
stripApexManifestRule = pctx.StaticRule("stripApexManifestRule", blueprint.RuleParams{
Command: `rm -f $out && ${conv_apex_manifest} strip $in -o $out`,
CommandDeps: []string{"${conv_apex_manifest}"},
@@ -107,6 +112,7 @@
`--canned_fs_config ${canned_fs_config} ` +
`--include_build_info ` +
`--payload_type image ` +
+ `--apex_version ${apex_version} ` +
`--key ${key} ${opt_flags} ${image_dir} ${out} `,
CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}",
"${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}", "${sload_f2fs}", "${make_erofs}",
@@ -114,7 +120,7 @@
Rspfile: "${out}.copy_commands",
RspfileContent: "${copy_commands}",
Description: "APEX ${image_dir} => ${out}",
- }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest", "payload_fs_type")
+ }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest", "payload_fs_type", "apex_version")
zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
@@ -122,12 +128,13 @@
`APEXER_TOOL_PATH=${tool_path} ` +
`${apexer} --force --manifest ${manifest} ` +
`--payload_type zip ` +
+ `--apex_version ${apex_version} ` +
`${image_dir} ${out} `,
CommandDeps: []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"},
Rspfile: "${out}.copy_commands",
RspfileContent: "${copy_commands}",
Description: "ZipAPEX ${image_dir} => ${out}",
- }, "tool_path", "image_dir", "copy_commands", "manifest")
+ }, "tool_path", "image_dir", "copy_commands", "manifest", "apex_version")
apexProtoConvertRule = pctx.AndroidStaticRule("apexProtoConvertRule",
blueprint.RuleParams{
@@ -205,10 +212,17 @@
optCommands = append(optCommands, "-a jniLibs "+strings.Join(jniLibs, " "))
}
+ manifestJsonCommentsStripped := android.PathForModuleOut(ctx, "apex_manifest_comments_stripped.json")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: stripCommentsApexManifestRule,
+ Input: src,
+ Output: manifestJsonCommentsStripped,
+ })
+
manifestJsonFullOut := android.PathForModuleOut(ctx, "apex_manifest_full.json")
ctx.Build(pctx, android.BuildParams{
Rule: apexManifestRule,
- Input: src,
+ Input: manifestJsonCommentsStripped,
Output: manifestJsonFullOut,
Args: map[string]string{
"provideNativeLibs": strings.Join(provideNativeLibs, " "),
@@ -655,8 +669,6 @@
optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String())
}
- optFlags = append(optFlags, "--apex_version "+defaultManifestVersion)
-
optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string())
ctx.Build(pctx, android.BuildParams{
@@ -672,6 +684,7 @@
"file_contexts": fileContexts.String(),
"canned_fs_config": cannedFsConfig.String(),
"key": a.privateKeyFile.String(),
+ "apex_version": defaultManifestVersion,
"opt_flags": strings.Join(optFlags, " "),
},
})
@@ -768,6 +781,7 @@
"image_dir": imageDir.String(),
"copy_commands": strings.Join(copyCommands, " && "),
"manifest": a.manifestPbOut.String(),
+ "apex_version": defaultManifestVersion,
},
})
}
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 6829698..ae2b107 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -21,7 +21,6 @@
"fmt"
"path/filepath"
"reflect"
- "regexp"
"sort"
"strings"
@@ -83,6 +82,7 @@
OutputIds []artifactId
TemplateContent string
Substitutions []KeyValuePair
+ FileContents string
}
// actionGraphContainer contains relevant portions of Bazel's aquery proto, ActionGraphContainer.
@@ -110,11 +110,14 @@
// input path string, but not both.
InputDepsetHashes []string
InputPaths []string
+ FileContents string
}
// A helper type for aquery processing which facilitates retrieval of path IDs from their
// less readable Bazel structures (depset and path fragment).
type aqueryArtifactHandler struct {
+ // Switches to true if any depset contains only `bazelToolsDependencySentinel`
+ bazelToolsDependencySentinelNeeded bool
// Maps depset id to AqueryDepset, a representation of depset which is
// post-processed for middleman artifact handling, unhandled artifact
// dropping, content hashing, etc.
@@ -137,12 +140,12 @@
"%python_binary%": "python3",
}
-// This pattern matches the MANIFEST file created for a py_binary target.
-var manifestFilePattern = regexp.MustCompile(".*/.+\\.runfiles/MANIFEST$")
-
// The file name of py3wrapper.sh, which is used by py_binary targets.
const py3wrapperFileName = "/py3wrapper.sh"
+// A file to be put into depsets that are otherwise empty
+const bazelToolsDependencySentinel = "BAZEL_TOOLS_DEPENDENCY_SENTINEL"
+
func indexBy[K comparable, V any](values []V, keyFn func(v V) K) map[K]V {
m := map[K]V{}
for _, v := range values {
@@ -219,20 +222,15 @@
if depsetsToUse, isMiddleman := middlemanIdToDepsetIds[artifactId]; isMiddleman {
// Swap middleman artifacts with their corresponding depsets and drop the middleman artifacts.
transitiveDepsetIds = append(transitiveDepsetIds, depsetsToUse...)
- } else if strings.HasSuffix(path, py3wrapperFileName) || manifestFilePattern.MatchString(path) {
+ } else if strings.HasSuffix(path, py3wrapperFileName) ||
+ strings.HasPrefix(path, "../bazel_tools") {
// Drop these artifacts.
// See go/python-binary-host-mixed-build for more details.
- // 1) For py3wrapper.sh, there is no action for creating py3wrapper.sh in the aquery output of
- // Bazel py_binary targets, so there is no Ninja build statements generated for creating it.
- // 2) For MANIFEST file, SourceSymlinkManifest action is in aquery output of Bazel py_binary targets,
- // but it doesn't contain sufficient information so no Ninja build statements are generated
- // for creating it.
- // So in mixed build mode, when these two are used as input of some Ninja build statement,
- // since there is no build statement to create them, they should be removed from input paths.
- // TODO(b/197135294): Clean up this custom runfiles handling logic when
- // SourceSymlinkManifest and SymlinkTree actions are supported.
+ // 1) Drop py3wrapper.sh, just use python binary, the launcher script generated by the
+ // TemplateExpandAction handles everything necessary to launch a Pythin application.
+ // 2) ../bazel_tools: they have MODIFY timestamp 10years in the future and would cause the
+ // containing depset to always be considered newer than their outputs.
} else {
- // TODO(b/216194240): Filter out bazel tools.
directArtifactPaths = append(directArtifactPaths, path)
}
}
@@ -249,6 +247,13 @@
}
childDepsetHashes = append(childDepsetHashes, childAqueryDepset.ContentHash)
}
+ if len(directArtifactPaths) == 0 && len(childDepsetHashes) == 0 {
+ // We could omit this depset altogether but that requires cleanup on
+ // transitive dependents.
+ // As a simpler alternative, we use this sentinel file as a dependency.
+ directArtifactPaths = append(directArtifactPaths, bazelToolsDependencySentinel)
+ a.bazelToolsDependencySentinelNeeded = true
+ }
aqueryDepset := AqueryDepset{
ContentHash: depsetContentHash(directArtifactPaths, childDepsetHashes),
DirectArtifacts: directArtifactPaths,
@@ -317,6 +322,13 @@
}
var buildStatements []BuildStatement
+ if aqueryHandler.bazelToolsDependencySentinelNeeded {
+ buildStatements = append(buildStatements, BuildStatement{
+ Command: fmt.Sprintf("touch '%s'", bazelToolsDependencySentinel),
+ OutputPaths: []string{bazelToolsDependencySentinel},
+ Mnemonic: bazelToolsDependencySentinel,
+ })
+ }
for _, actionEntry := range aqueryResult.Actions {
if shouldSkipAction(actionEntry) {
@@ -324,12 +336,14 @@
}
var buildStatement BuildStatement
- if isSymlinkAction(actionEntry) {
+ if actionEntry.isSymlinkAction() {
buildStatement, err = aqueryHandler.symlinkActionBuildStatement(actionEntry)
- } else if isTemplateExpandAction(actionEntry) && len(actionEntry.Arguments) < 1 {
+ } else if actionEntry.isTemplateExpandAction() && len(actionEntry.Arguments) < 1 {
buildStatement, err = aqueryHandler.templateExpandActionBuildStatement(actionEntry)
- } else if isPythonZipperAction(actionEntry) {
- buildStatement, err = aqueryHandler.pythonZipperActionBuildStatement(actionEntry, buildStatements)
+ } 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 {
@@ -430,54 +444,6 @@
return buildStatement, nil
}
-func (a *aqueryArtifactHandler) pythonZipperActionBuildStatement(actionEntry action, prevBuildStatements []BuildStatement) (BuildStatement, error) {
- inputPaths, err := a.getInputPaths(actionEntry.InputDepSetIds)
- if err != nil {
- return BuildStatement{}, err
- }
- outputPaths, depfile, err := a.getOutputPaths(actionEntry)
- if err != nil {
- return BuildStatement{}, err
- }
-
- if len(inputPaths) < 1 || len(outputPaths) != 1 {
- return BuildStatement{}, fmt.Errorf("Expect 1+ input and 1 output to python zipper action, got: input %q, output %q", inputPaths, outputPaths)
- }
- command := strings.Join(proptools.ShellEscapeListIncludingSpaces(actionEntry.Arguments), " ")
- inputPaths, command = removePy3wrapperScript(inputPaths, command)
- command = addCommandForPyBinaryRunfilesDir(command, inputPaths[0], outputPaths[0])
- // Add the python zip file as input of the corresponding python binary stub script in Ninja build statements.
- // In Ninja build statements, the outputs of dependents of a python binary have python binary stub script as input,
- // which is not sufficient without the python zip file from which runfiles directory is created for py_binary.
- //
- // The following logic relies on that Bazel aquery output returns actions in the order that
- // PythonZipper is after TemplateAction of creating Python binary stub script. If later Bazel doesn't return actions
- // in that order, the following logic might not find the build statement generated for Python binary
- // stub script and the build might fail. So the check of pyBinaryFound is added to help debug in case later Bazel might change aquery output.
- // See go/python-binary-host-mixed-build for more details.
- pythonZipFilePath := outputPaths[0]
- pyBinaryFound := false
- for i := range prevBuildStatements {
- if len(prevBuildStatements[i].OutputPaths) == 1 && prevBuildStatements[i].OutputPaths[0]+".zip" == pythonZipFilePath {
- prevBuildStatements[i].InputPaths = append(prevBuildStatements[i].InputPaths, pythonZipFilePath)
- pyBinaryFound = true
- }
- }
- if !pyBinaryFound {
- return BuildStatement{}, fmt.Errorf("Could not find the correspondinging Python binary stub script of PythonZipper: %q", outputPaths)
- }
-
- buildStatement := BuildStatement{
- Command: command,
- Depfile: depfile,
- OutputPaths: outputPaths,
- InputPaths: inputPaths,
- Env: actionEntry.EnvironmentVariables,
- Mnemonic: actionEntry.Mnemonic,
- }
- return buildStatement, nil
-}
-
func (a *aqueryArtifactHandler) templateExpandActionBuildStatement(actionEntry action) (BuildStatement, error) {
outputPaths, depfile, err := a.getOutputPaths(actionEntry)
if err != nil {
@@ -510,6 +476,47 @@
return buildStatement, nil
}
+func (a *aqueryArtifactHandler) fileWriteActionBuildStatement(actionEntry 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 BuildStatement{
+ Depfile: nil,
+ OutputPaths: outputPaths,
+ Env: actionEntry.EnvironmentVariables,
+ Mnemonic: actionEntry.Mnemonic,
+ InputDepsetHashes: depsetHashes,
+ FileContents: actionEntry.FileContents,
+ }, nil
+}
+
+func (a *aqueryArtifactHandler) symlinkTreeActionBuildStatement(actionEntry action) (BuildStatement, error) {
+ outputPaths, _, err := a.getOutputPaths(actionEntry)
+ if err != nil {
+ return BuildStatement{}, err
+ }
+ inputPaths, err := a.getInputPaths(actionEntry.InputDepSetIds)
+ if err != nil {
+ return BuildStatement{}, 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)
+ }
+ // The actual command is generated in bazelSingleton.GenerateBuildActions
+ return BuildStatement{
+ Depfile: nil,
+ OutputPaths: outputPaths,
+ Env: actionEntry.EnvironmentVariables,
+ Mnemonic: actionEntry.Mnemonic,
+ InputPaths: inputPaths,
+ }, nil
+}
+
func (a *aqueryArtifactHandler) symlinkActionBuildStatement(actionEntry action) (BuildStatement, error) {
outputPaths, depfile, err := a.getOutputPaths(actionEntry)
if err != nil {
@@ -592,76 +599,35 @@
return replacer.Replace(str)
}
-// removePy3wrapperScript removes py3wrapper.sh from the input paths and command of the action of
-// creating python zip file in mixed build mode. py3wrapper.sh is returned as input by aquery but
-// there is no action returned by aquery for creating it. So in mixed build "python3" is used
-// as the PYTHON_BINARY in python binary stub script, and py3wrapper.sh is not needed and should be
-// removed from input paths and command of creating python zip file.
-// See go/python-binary-host-mixed-build for more details.
-// TODO(b/205879240) remove this after py3wrapper.sh could be created in the mixed build mode.
-func removePy3wrapperScript(inputPaths []string, command string) (newInputPaths []string, newCommand string) {
- // Remove from inputs
- filteredInputPaths := []string{}
- for _, path := range inputPaths {
- if !strings.HasSuffix(path, py3wrapperFileName) {
- filteredInputPaths = append(filteredInputPaths, path)
- }
- }
- newInputPaths = filteredInputPaths
-
- // Remove from command line
- var re = regexp.MustCompile(`\S*` + py3wrapperFileName)
- newCommand = re.ReplaceAllString(command, "")
- return
-}
-
-// addCommandForPyBinaryRunfilesDir adds commands creating python binary runfiles directory.
-// runfiles directory is created by using MANIFEST file and MANIFEST file is the output of
-// SourceSymlinkManifest action is in aquery output of Bazel py_binary targets,
-// but since SourceSymlinkManifest doesn't contain sufficient information
-// so MANIFEST file could not be created, which also blocks the creation of runfiles directory.
-// See go/python-binary-host-mixed-build for more details.
-// TODO(b/197135294) create runfiles directory from MANIFEST file once it can be created from SourceSymlinkManifest action.
-func addCommandForPyBinaryRunfilesDir(oldCommand string, zipperCommandPath, zipFilePath string) string {
- // Unzip the zip file, zipFilePath looks like <python_binary>.zip
- runfilesDirName := zipFilePath[0:len(zipFilePath)-4] + ".runfiles"
- command := fmt.Sprintf("%s x %s -d %s", zipperCommandPath, zipFilePath, runfilesDirName)
- // Create a symbolic link in <python_binary>.runfiles/, which is the expected structure
- // when running the python binary stub script.
- command += fmt.Sprintf(" && ln -sf runfiles/__main__ %s", runfilesDirName)
- return oldCommand + " && " + command
-}
-
-func isSymlinkAction(a action) bool {
+func (a action) isSymlinkAction() bool {
return a.Mnemonic == "Symlink" || a.Mnemonic == "SolibSymlink" || a.Mnemonic == "ExecutableSymlink"
}
-func isTemplateExpandAction(a action) bool {
+func (a action) isTemplateExpandAction() bool {
return a.Mnemonic == "TemplateExpand"
}
-func isPythonZipperAction(a action) bool {
- return a.Mnemonic == "PythonZipper"
+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 {
- // TODO(b/180945121): Handle complex symlink actions.
- if a.Mnemonic == "SymlinkTree" || a.Mnemonic == "SourceSymlinkManifest" {
- return true
- }
// 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
}
- // Skip "Fail" actions, which are placeholder actions designed to always fail.
- if a.Mnemonic == "Fail" {
+ // PythonZipper is bogus action returned by aquery, ignore it (b/236198693)
+ if a.Mnemonic == "PythonZipper" {
return true
}
- // TODO(b/180946980): Handle FileWrite. The aquery proto currently contains no information
- // about the contents that are written.
- if a.Mnemonic == "FileWrite" {
+ // Skip "Fail" actions, which are placeholder actions designed to always fail.
+ if a.Mnemonic == "Fail" {
return true
}
if a.Mnemonic == "BaselineCoverage" {
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 1da6340..3a2bf0f 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -25,28 +25,14 @@
// This input string is retrieved from a real build of bionic-related genrules.
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 6
- }, {
- "id": 3,
- "pathFragmentId": 8
- }, {
- "id": 4,
- "pathFragmentId": 12
- }, {
- "id": 5,
- "pathFragmentId": 19
- }, {
- "id": 6,
- "pathFragmentId": 20
- }, {
- "id": 7,
- "pathFragmentId": 21
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 6 },
+ { "id": 3, "pathFragmentId": 8 },
+ { "id": 4, "pathFragmentId": 12 },
+ { "id": 5, "pathFragmentId": 19 },
+ { "id": 6, "pathFragmentId": 20 },
+ { "id": 7, "pathFragmentId": 21 }],
"actions": [{
"targetId": 1,
"actionKey": "ab53f6ecbdc2ee8cb8812613b63205464f1f5083f6dca87081a0a398c0f1ecf7",
@@ -100,129 +86,45 @@
"outputIds": [7],
"primaryOutputId": 7
}],
- "targets": [{
- "id": 1,
- "label": "@sourceroot//bionic/libc:syscalls-arm",
- "ruleClassId": 1
- }, {
- "id": 2,
- "label": "@sourceroot//bionic/libc:syscalls-x86",
- "ruleClassId": 1
- }, {
- "id": 3,
- "label": "@sourceroot//bionic/libc:syscalls-x86_64",
- "ruleClassId": 1
- }, {
- "id": 4,
- "label": "@sourceroot//bionic/libc:syscalls-arm64",
- "ruleClassId": 1
- }],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 2, 3]
- }, {
- "id": 2,
- "directArtifactIds": [1, 2, 3]
- }, {
- "id": 3,
- "directArtifactIds": [1, 2, 3]
- }, {
- "id": 4,
- "directArtifactIds": [1, 2, 3]
- }],
+ "targets": [
+ { "id": 1, "label": "@sourceroot//bionic/libc:syscalls-arm", "ruleClassId": 1 },
+ { "id": 2, "label": "@sourceroot//bionic/libc:syscalls-x86", "ruleClassId": 1 },
+ { "id": 3, "label": "@sourceroot//bionic/libc:syscalls-x86_64", "ruleClassId": 1 },
+ { "id": 4, "label": "@sourceroot//bionic/libc:syscalls-arm64", "ruleClassId": 1 }],
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 2, 3] },
+ { "id": 2, "directArtifactIds": [1, 2, 3] },
+ { "id": 3, "directArtifactIds": [1, 2, 3] },
+ { "id": 4, "directArtifactIds": [1, 2, 3] }],
"configuration": [{
"id": 1,
"mnemonic": "k8-fastbuild",
"platformName": "k8",
"checksum": "485c362832c178e367d972177f68e69e0981e51e67ef1c160944473db53fe046"
}],
- "ruleClasses": [{
- "id": 1,
- "name": "genrule"
- }],
- "pathFragments": [{
- "id": 5,
- "label": ".."
- }, {
- "id": 4,
- "label": "sourceroot",
- "parentId": 5
- }, {
- "id": 3,
- "label": "bionic",
- "parentId": 4
- }, {
- "id": 2,
- "label": "libc",
- "parentId": 3
- }, {
- "id": 1,
- "label": "SYSCALLS.TXT",
- "parentId": 2
- }, {
- "id": 7,
- "label": "tools",
- "parentId": 2
- }, {
- "id": 6,
- "label": "gensyscalls.py",
- "parentId": 7
- }, {
- "id": 11,
- "label": "bazel_tools",
- "parentId": 5
- }, {
- "id": 10,
- "label": "tools",
- "parentId": 11
- }, {
- "id": 9,
- "label": "genrule",
- "parentId": 10
- }, {
- "id": 8,
- "label": "genrule-setup.sh",
- "parentId": 9
- }, {
- "id": 18,
- "label": "bazel-out"
- }, {
- "id": 17,
- "label": "sourceroot",
- "parentId": 18
- }, {
- "id": 16,
- "label": "k8-fastbuild",
- "parentId": 17
- }, {
- "id": 15,
- "label": "bin",
- "parentId": 16
- }, {
- "id": 14,
- "label": "bionic",
- "parentId": 15
- }, {
- "id": 13,
- "label": "libc",
- "parentId": 14
- }, {
- "id": 12,
- "label": "syscalls-arm.S",
- "parentId": 13
- }, {
- "id": 19,
- "label": "syscalls-x86.S",
- "parentId": 13
- }, {
- "id": 20,
- "label": "syscalls-x86_64.S",
- "parentId": 13
- }, {
- "id": 21,
- "label": "syscalls-arm64.S",
- "parentId": 13
- }]
+ "ruleClasses": [{ "id": 1, "name": "genrule"}],
+ "pathFragments": [
+ { "id": 5, "label": ".." },
+ { "id": 4, "label": "sourceroot", "parentId": 5 },
+ { "id": 3, "label": "bionic", "parentId": 4 },
+ { "id": 2, "label": "libc", "parentId": 3 },
+ { "id": 1, "label": "SYSCALLS.TXT", "parentId": 2 },
+ { "id": 7, "label": "tools", "parentId": 2 },
+ { "id": 6, "label": "gensyscalls.py", "parentId": 7 },
+ { "id": 11, "label": "bazel_tools", "parentId": 5 },
+ { "id": 10, "label": "tools", "parentId": 11 },
+ { "id": 9, "label": "genrule", "parentId": 10 },
+ { "id": 8, "label": "genrule-setup.sh", "parentId": 9 },
+ { "id": 18, "label": "bazel-out" },
+ { "id": 17, "label": "sourceroot", "parentId": 18 },
+ { "id": 16, "label": "k8-fastbuild", "parentId": 17 },
+ { "id": 15, "label": "bin", "parentId": 16 },
+ { "id": 14, "label": "bionic", "parentId": 15 },
+ { "id": 13, "label": "libc", "parentId": 14 },
+ { "id": 12, "label": "syscalls-arm.S", "parentId": 13 },
+ { "id": 19, "label": "syscalls-x86.S", "parentId": 13 },
+ { "id": 20, "label": "syscalls-x86_64.S", "parentId": 13 },
+ { "id": 21, "label": "syscalls-arm64.S", "parentId": 13 }]
}`
actualbuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
var expectedBuildStatements []BuildStatement
@@ -246,7 +148,6 @@
expectedFlattenedInputs := []string{
"../sourceroot/bionic/libc/SYSCALLS.TXT",
"../sourceroot/bionic/libc/tools/gensyscalls.py",
- "../bazel_tools/tools/genrule/genrule-setup.sh",
}
// In this example, each depset should have the same expected inputs.
for _, actualDepset := range actualDepsets {
@@ -260,13 +161,9 @@
func TestInvalidOutputId(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -276,17 +173,11 @@
"outputIds": [3],
"primaryOutputId": 3
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 2]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "two"
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 2] }],
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "two" }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
@@ -296,13 +187,9 @@
func TestInvalidInputDepsetIdFromAction(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -312,17 +199,11 @@
"outputIds": [1],
"primaryOutputId": 1
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 2]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "two"
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 2] }],
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "two" }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
@@ -332,13 +213,9 @@
func TestInvalidInputDepsetIdFromDepset(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -348,18 +225,11 @@
"outputIds": [1],
"primaryOutputId": 1
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 2],
- "transitiveDepSetIds": [42]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "two"
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 2], "transitiveDepSetIds": [42] }],
+ "pathFragments": [
+ { "id": 1, "label": "one"},
+ { "id": 2, "label": "two" }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
@@ -369,13 +239,9 @@
func TestInvalidInputArtifactId(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -385,17 +251,11 @@
"outputIds": [1],
"primaryOutputId": 1
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 3]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "two"
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 3] }],
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "two" }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
@@ -405,13 +265,9 @@
func TestInvalidPathFragmentId(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -421,18 +277,11 @@
"outputIds": [1],
"primaryOutputId": 1
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 2]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "two",
- "parentId": 3
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 2] }],
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "two", "parentId": 3 }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
@@ -442,16 +291,10 @@
func TestDepfiles(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }, {
- "id": 3,
- "pathFragmentId": 3
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 },
+ { "id": 3, "pathFragmentId": 3 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -461,20 +304,12 @@
"outputIds": [2, 3],
"primaryOutputId": 2
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 2, 3]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "two"
- }, {
- "id": 3,
- "label": "two.d"
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 2, 3] }],
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "two" },
+ { "id": 3, "label": "two.d" }]
}`
actual, _, err := AqueryBuildStatements([]byte(inputString))
@@ -497,19 +332,11 @@
func TestMultipleDepfiles(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }, {
- "id": 3,
- "pathFragmentId": 3
- }, {
- "id": 4,
- "pathFragmentId": 4
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 },
+ { "id": 3, "pathFragmentId": 3 },
+ { "id": 4, "pathFragmentId": 4 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -523,19 +350,11 @@
"id": 1,
"directArtifactIds": [1, 2, 3, 4]
}],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "two"
- }, {
- "id": 3,
- "label": "two.d"
- }, {
- "id": 4,
- "label": "other.d"
- }]
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "two" },
+ { "id": 3, "label": "two.d" },
+ { "id": 4, "label": "other.d" }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
@@ -547,70 +366,28 @@
// a single action with many inputs given via a deep depset.
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 7
- }, {
- "id": 3,
- "pathFragmentId": 8
- }, {
- "id": 4,
- "pathFragmentId": 9
- }, {
- "id": 5,
- "pathFragmentId": 10
- }, {
- "id": 6,
- "pathFragmentId": 11
- }, {
- "id": 7,
- "pathFragmentId": 12
- }, {
- "id": 8,
- "pathFragmentId": 13
- }, {
- "id": 9,
- "pathFragmentId": 14
- }, {
- "id": 10,
- "pathFragmentId": 15
- }, {
- "id": 11,
- "pathFragmentId": 16
- }, {
- "id": 12,
- "pathFragmentId": 17
- }, {
- "id": 13,
- "pathFragmentId": 18
- }, {
- "id": 14,
- "pathFragmentId": 19
- }, {
- "id": 15,
- "pathFragmentId": 20
- }, {
- "id": 16,
- "pathFragmentId": 21
- }, {
- "id": 17,
- "pathFragmentId": 22
- }, {
- "id": 18,
- "pathFragmentId": 23
- }, {
- "id": 19,
- "pathFragmentId": 24
- }, {
- "id": 20,
- "pathFragmentId": 25
- }, {
- "id": 21,
- "pathFragmentId": 26
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 7 },
+ { "id": 3, "pathFragmentId": 8 },
+ { "id": 4, "pathFragmentId": 9 },
+ { "id": 5, "pathFragmentId": 10 },
+ { "id": 6, "pathFragmentId": 11 },
+ { "id": 7, "pathFragmentId": 12 },
+ { "id": 8, "pathFragmentId": 13 },
+ { "id": 9, "pathFragmentId": 14 },
+ { "id": 10, "pathFragmentId": 15 },
+ { "id": 11, "pathFragmentId": 16 },
+ { "id": 12, "pathFragmentId": 17 },
+ { "id": 13, "pathFragmentId": 18 },
+ { "id": 14, "pathFragmentId": 19 },
+ { "id": 15, "pathFragmentId": 20 },
+ { "id": 16, "pathFragmentId": 21 },
+ { "id": 17, "pathFragmentId": 22 },
+ { "id": 18, "pathFragmentId": 23 },
+ { "id": 19, "pathFragmentId": 24 },
+ { "id": 20, "pathFragmentId": 25 },
+ { "id": 21, "pathFragmentId": 26 }],
"actions": [{
"targetId": 1,
"actionKey": "3b826d17fadbbbcd8313e456b90ec47c078c438088891dd45b4adbcd8889dc50",
@@ -621,128 +398,39 @@
"outputIds": [21],
"primaryOutputId": 21
}],
- "depSetOfFiles": [{
- "id": 3,
- "directArtifactIds": [1, 2, 3, 4, 5]
- }, {
- "id": 4,
- "directArtifactIds": [6, 7, 8, 9, 10]
- }, {
- "id": 2,
- "transitiveDepSetIds": [3, 4],
- "directArtifactIds": [11, 12, 13, 14, 15]
- }, {
- "id": 5,
- "directArtifactIds": [16, 17, 18, 19]
- }, {
- "id": 1,
- "transitiveDepSetIds": [2, 5],
- "directArtifactIds": [20]
- }],
- "pathFragments": [{
- "id": 6,
- "label": "bazel-out"
- }, {
- "id": 5,
- "label": "sourceroot",
- "parentId": 6
- }, {
- "id": 4,
- "label": "k8-fastbuild",
- "parentId": 5
- }, {
- "id": 3,
- "label": "bin",
- "parentId": 4
- }, {
- "id": 2,
- "label": "testpkg",
- "parentId": 3
- }, {
- "id": 1,
- "label": "test_1",
- "parentId": 2
- }, {
- "id": 7,
- "label": "test_2",
- "parentId": 2
- }, {
- "id": 8,
- "label": "test_3",
- "parentId": 2
- }, {
- "id": 9,
- "label": "test_4",
- "parentId": 2
- }, {
- "id": 10,
- "label": "test_5",
- "parentId": 2
- }, {
- "id": 11,
- "label": "test_6",
- "parentId": 2
- }, {
- "id": 12,
- "label": "test_7",
- "parentId": 2
- }, {
- "id": 13,
- "label": "test_8",
- "parentId": 2
- }, {
- "id": 14,
- "label": "test_9",
- "parentId": 2
- }, {
- "id": 15,
- "label": "test_10",
- "parentId": 2
- }, {
- "id": 16,
- "label": "test_11",
- "parentId": 2
- }, {
- "id": 17,
- "label": "test_12",
- "parentId": 2
- }, {
- "id": 18,
- "label": "test_13",
- "parentId": 2
- }, {
- "id": 19,
- "label": "test_14",
- "parentId": 2
- }, {
- "id": 20,
- "label": "test_15",
- "parentId": 2
- }, {
- "id": 21,
- "label": "test_16",
- "parentId": 2
- }, {
- "id": 22,
- "label": "test_17",
- "parentId": 2
- }, {
- "id": 23,
- "label": "test_18",
- "parentId": 2
- }, {
- "id": 24,
- "label": "test_19",
- "parentId": 2
- }, {
- "id": 25,
- "label": "test_root",
- "parentId": 2
- }, {
- "id": 26,
- "label": "test_out",
- "parentId": 2
- }]
+ "depSetOfFiles": [
+ { "id": 3, "directArtifactIds": [1, 2, 3, 4, 5] },
+ { "id": 4, "directArtifactIds": [6, 7, 8, 9, 10] },
+ { "id": 2, "transitiveDepSetIds": [3, 4], "directArtifactIds": [11, 12, 13, 14, 15] },
+ { "id": 5, "directArtifactIds": [16, 17, 18, 19] },
+ { "id": 1, "transitiveDepSetIds": [2, 5], "directArtifactIds": [20] }],
+ "pathFragments": [
+ { "id": 6, "label": "bazel-out" },
+ { "id": 5, "label": "sourceroot", "parentId": 6 },
+ { "id": 4, "label": "k8-fastbuild", "parentId": 5 },
+ { "id": 3, "label": "bin", "parentId": 4 },
+ { "id": 2, "label": "testpkg", "parentId": 3 },
+ { "id": 1, "label": "test_1", "parentId": 2 },
+ { "id": 7, "label": "test_2", "parentId": 2 },
+ { "id": 8, "label": "test_3", "parentId": 2 },
+ { "id": 9, "label": "test_4", "parentId": 2 },
+ { "id": 10, "label": "test_5", "parentId": 2 },
+ { "id": 11, "label": "test_6", "parentId": 2 },
+ { "id": 12, "label": "test_7", "parentId": 2 },
+ { "id": 13, "label": "test_8", "parentId": 2 },
+ { "id": 14, "label": "test_9", "parentId": 2 },
+ { "id": 15, "label": "test_10", "parentId": 2 },
+ { "id": 16, "label": "test_11", "parentId": 2 },
+ { "id": 17, "label": "test_12", "parentId": 2 },
+ { "id": 18, "label": "test_13", "parentId": 2 },
+ { "id": 19, "label": "test_14", "parentId": 2 },
+ { "id": 20, "label": "test_15", "parentId": 2 },
+ { "id": 21, "label": "test_16", "parentId": 2 },
+ { "id": 22, "label": "test_17", "parentId": 2 },
+ { "id": 23, "label": "test_18", "parentId": 2 },
+ { "id": 24, "label": "test_19", "parentId": 2 },
+ { "id": 25, "label": "test_root", "parentId": 2 },
+ { "id": 26,"label": "test_out", "parentId": 2 }]
}`
actualbuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
@@ -772,54 +460,149 @@
}
}
+func TestSymlinkTree(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "SymlinkTree",
+ "configurationId": 1,
+ "inputDepSetIds": [1],
+ "outputIds": [2],
+ "primaryOutputId": 2,
+ "executionPlatform": "//build/bazel/platforms:linux_x86_64"
+ }],
+ "pathFragments": [
+ { "id": 1, "label": "foo.manifest" },
+ { "id": 2, "label": "foo.runfiles/MANIFEST" }],
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1] }]
+}
+`
+ actual, _, err := AqueryBuildStatements([]byte(inputString))
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ }
+ assertBuildStatements(t, []BuildStatement{
+ {
+ Command: "",
+ OutputPaths: []string{"foo.runfiles/MANIFEST"},
+ Mnemonic: "SymlinkTree",
+ InputPaths: []string{"foo.manifest"},
+ },
+ }, actual)
+}
+
+func TestBazelOutRemovalFromInputDepsets(t *testing.T) {
+ const inputString = `{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 10
+ }, {
+ "id": 2,
+ "pathFragmentId": 20
+ }, {
+ "id": 3,
+ "pathFragmentId": 30
+ }, {
+ "id": 4,
+ "pathFragmentId": 40
+ }],
+ "depSetOfFiles": [{
+ "id": 1111,
+ "directArtifactIds": [3 , 4]
+ }],
+ "actions": [{
+ "targetId": 100,
+ "actionKey": "x",
+ "inputDepSetIds": [1111],
+ "mnemonic": "x",
+ "arguments": ["bogus", "command"],
+ "outputIds": [2],
+ "primaryOutputId": 1
+ }],
+ "pathFragments": [{
+ "id": 10,
+ "label": "input"
+ }, {
+ "id": 20,
+ "label": "output"
+ }, {
+ "id": 30,
+ "label": "dep1",
+ "parentId": 50
+ }, {
+ "id": 40,
+ "label": "dep2",
+ "parentId": 60
+ }, {
+ "id": 50,
+ "label": "bazel_tools",
+ "parentId": 60
+ }, {
+ "id": 60,
+ "label": ".."
+ }]
+}`
+ actualBuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
+ if len(actualDepsets) != 1 {
+ t.Errorf("expected 1 depset but found %#v", actualDepsets)
+ return
+ }
+ dep2Found := false
+ for _, dep := range flattenDepsets([]string{actualDepsets[0].ContentHash}, actualDepsets) {
+ if dep == "../bazel_tools/dep1" {
+ t.Errorf("dependency %s expected to be removed but still exists", dep)
+ } else if dep == "../dep2" {
+ dep2Found = true
+ }
+ }
+ if !dep2Found {
+ t.Errorf("dependency ../dep2 expected but not found")
+ }
+
+ expectedBuildStatement := BuildStatement{
+ Command: "bogus command",
+ OutputPaths: []string{"output"},
+ Mnemonic: "x",
+ }
+ buildStatementFound := false
+ for _, actualBuildStatement := range actualBuildStatements {
+ if buildStatementEquals(actualBuildStatement, expectedBuildStatement) == "" {
+ buildStatementFound = true
+ break
+ }
+ }
+ if !buildStatementFound {
+ t.Errorf("expected but missing %#v in %#v", expectedBuildStatement, actualBuildStatements)
+ return
+ }
+}
+
func TestMiddlemenAction(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }, {
- "id": 3,
- "pathFragmentId": 3
- }, {
- "id": 4,
- "pathFragmentId": 4
- }, {
- "id": 5,
- "pathFragmentId": 5
- }, {
- "id": 6,
- "pathFragmentId": 6
- }],
- "pathFragments": [{
- "id": 1,
- "label": "middleinput_one"
- }, {
- "id": 2,
- "label": "middleinput_two"
- }, {
- "id": 3,
- "label": "middleman_artifact"
- }, {
- "id": 4,
- "label": "maininput_one"
- }, {
- "id": 5,
- "label": "maininput_two"
- }, {
- "id": 6,
- "label": "output"
- }],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 2]
- }, {
- "id": 2,
- "directArtifactIds": [3, 4, 5]
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 },
+ { "id": 3, "pathFragmentId": 3 },
+ { "id": 4, "pathFragmentId": 4 },
+ { "id": 5, "pathFragmentId": 5 },
+ { "id": 6, "pathFragmentId": 6 }],
+ "pathFragments": [
+ { "id": 1, "label": "middleinput_one" },
+ { "id": 2, "label": "middleinput_two" },
+ { "id": 3, "label": "middleman_artifact" },
+ { "id": 4, "label": "maininput_one" },
+ { "id": 5, "label": "maininput_two" },
+ { "id": 6, "label": "output" }],
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 2] },
+ { "id": 2, "directArtifactIds": [3, 4, 5] }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -911,13 +694,9 @@
func TestSimpleSymlink(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 3
- }, {
- "id": 2,
- "pathFragmentId": 5
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 3 },
+ { "id": 2, "pathFragmentId": 5 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -926,30 +705,14 @@
"outputIds": [2],
"primaryOutputId": 2
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "file_subdir",
- "parentId": 1
- }, {
- "id": 3,
- "label": "file",
- "parentId": 2
- }, {
- "id": 4,
- "label": "symlink_subdir",
- "parentId": 1
- }, {
- "id": 5,
- "label": "symlink",
- "parentId": 4
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1] }],
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "file_subdir", "parentId": 1 },
+ { "id": 3, "label": "file", "parentId": 2 },
+ { "id": 4, "label": "symlink_subdir", "parentId": 1 },
+ { "id": 5, "label": "symlink", "parentId": 4 }]
}`
actual, _, err := AqueryBuildStatements([]byte(inputString))
@@ -975,13 +738,9 @@
func TestSymlinkQuotesPaths(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 3
- }, {
- "id": 2,
- "pathFragmentId": 5
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 3 },
+ { "id": 2, "pathFragmentId": 5 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -990,30 +749,14 @@
"outputIds": [2],
"primaryOutputId": 2
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "file subdir",
- "parentId": 1
- }, {
- "id": 3,
- "label": "file",
- "parentId": 2
- }, {
- "id": 4,
- "label": "symlink subdir",
- "parentId": 1
- }, {
- "id": 5,
- "label": "symlink",
- "parentId": 4
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1] }],
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "file subdir", "parentId": 1 },
+ { "id": 3, "label": "file", "parentId": 2 },
+ { "id": 4, "label": "symlink subdir", "parentId": 1 },
+ { "id": 5, "label": "symlink", "parentId": 4 }]
}`
actual, _, err := AqueryBuildStatements([]byte(inputString))
@@ -1039,16 +782,10 @@
func TestSymlinkMultipleInputs(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }, {
- "id": 3,
- "pathFragmentId": 3
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 },
+ { "id": 3, "pathFragmentId": 3 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -1057,20 +794,11 @@
"outputIds": [3],
"primaryOutputId": 3
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1,2]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "file"
- }, {
- "id": 2,
- "label": "other_file"
- }, {
- "id": 3,
- "label": "symlink"
- }]
+ "depSetOfFiles": [{ "id": 1, "directArtifactIds": [1,2] }],
+ "pathFragments": [
+ { "id": 1, "label": "file" },
+ { "id": 2, "label": "other_file" },
+ { "id": 3, "label": "symlink" }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
@@ -1080,16 +808,10 @@
func TestSymlinkMultipleOutputs(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }, {
- "id": 3,
- "pathFragmentId": 3
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 },
+ { "id": 3, "pathFragmentId": 3 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -1098,20 +820,12 @@
"outputIds": [2,3],
"primaryOutputId": 2
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "file"
- }, {
- "id": 2,
- "label": "symlink"
- }, {
- "id": 3,
- "label": "other_symlink"
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1] }],
+ "pathFragments": [
+ { "id": 1, "label": "file" },
+ { "id": 2, "label": "symlink" },
+ { "id": 3, "label": "other_symlink" }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
@@ -1134,18 +848,12 @@
"primaryOutputId": 1,
"executionPlatform": "//build/bazel/platforms:linux_x86_64",
"templateContent": "Test template substitutions: %token1%, %python_binary%",
- "substitutions": [{
- "key": "%token1%",
- "value": "abcd"
- },{
- "key": "%python_binary%",
- "value": "python3"
- }]
+ "substitutions": [
+ { "key": "%token1%", "value": "abcd" },
+ { "key": "%python_binary%", "value": "python3" }]
}],
- "pathFragments": [{
- "id": 1,
- "label": "template_file"
- }]
+ "pathFragments": [
+ { "id": 1, "label": "template_file" }]
}`
actual, _, err := AqueryBuildStatements([]byte(inputString))
@@ -1168,10 +876,8 @@
func TestTemplateExpandActionNoOutput(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -1180,291 +886,79 @@
"primaryOutputId": 1,
"executionPlatform": "//build/bazel/platforms:linux_x86_64",
"templateContent": "Test template substitutions: %token1%, %python_binary%",
- "substitutions": [{
- "key": "%token1%",
- "value": "abcd"
- },{
- "key": "%python_binary%",
- "value": "python3"
- }]
+ "substitutions": [
+ { "key": "%token1%", "value": "abcd" },
+ { "key": "%python_binary%", "value": "python3" }]
}],
- "pathFragments": [{
- "id": 1,
- "label": "template_file"
- }]
+ "pathFragments": [
+ { "id": 1, "label": "template_file" }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
assertError(t, err, `Expect 1 output to template expand action, got: output []`)
}
-func TestPythonZipperActionSuccess(t *testing.T) {
+func TestFileWrite(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- },{
- "id": 2,
- "pathFragmentId": 2
- },{
- "id": 3,
- "pathFragmentId": 3
- },{
- "id": 4,
- "pathFragmentId": 4
- },{
- "id": 5,
- "pathFragmentId": 10
- },{
- "id": 10,
- "pathFragmentId": 20
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
- "mnemonic": "TemplateExpand",
+ "mnemonic": "FileWrite",
"configurationId": 1,
"outputIds": [1],
"primaryOutputId": 1,
"executionPlatform": "//build/bazel/platforms:linux_x86_64",
- "templateContent": "Test template substitutions: %token1%, %python_binary%",
- "substitutions": [{
- "key": "%token1%",
- "value": "abcd"
- },{
- "key": "%python_binary%",
- "value": "python3"
- }]
- },{
- "targetId": 1,
- "actionKey": "x",
- "mnemonic": "PythonZipper",
- "configurationId": 1,
- "arguments": ["../bazel_tools/tools/zip/zipper/zipper", "cC", "python_binary.zip", "__main__.py\u003dbazel-out/k8-fastbuild/bin/python_binary.temp", "__init__.py\u003d", "runfiles/__main__/__init__.py\u003d", "runfiles/__main__/python_binary.py\u003dpython_binary.py", "runfiles/bazel_tools/tools/python/py3wrapper.sh\u003dbazel-out/bazel_tools/k8-fastbuild/bin/tools/python/py3wrapper.sh"],
- "outputIds": [2],
- "inputDepSetIds": [1],
- "primaryOutputId": 2
+ "fileContents": "file data\n"
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [4, 3, 5]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "python_binary"
- },{
- "id": 2,
- "label": "python_binary.zip"
- },{
- "id": 3,
- "label": "python_binary.py"
- },{
- "id": 9,
- "label": ".."
- }, {
- "id": 8,
- "label": "bazel_tools",
- "parentId": 9
- }, {
- "id": 7,
- "label": "tools",
- "parentId": 8
- }, {
- "id": 6,
- "label": "zip",
- "parentId": 7
- }, {
- "id": 5,
- "label": "zipper",
- "parentId": 6
- }, {
- "id": 4,
- "label": "zipper",
- "parentId": 5
- },{
- "id": 16,
- "label": "bazel-out"
- },{
- "id": 15,
- "label": "bazel_tools",
- "parentId": 16
- }, {
- "id": 14,
- "label": "k8-fastbuild",
- "parentId": 15
- }, {
- "id": 13,
- "label": "bin",
- "parentId": 14
- }, {
- "id": 12,
- "label": "tools",
- "parentId": 13
- }, {
- "id": 11,
- "label": "python",
- "parentId": 12
- }, {
- "id": 10,
- "label": "py3wrapper.sh",
- "parentId": 11
- },{
- "id": 20,
- "label": "python_binary"
- }]
-}`
+ "pathFragments": [
+ { "id": 1, "label": "foo.manifest" }]
+}
+`
actual, _, err := AqueryBuildStatements([]byte(inputString))
-
if err != nil {
t.Errorf("Unexpected error %q", err)
}
+ assertBuildStatements(t, []BuildStatement{
+ {
+ OutputPaths: []string{"foo.manifest"},
+ Mnemonic: "FileWrite",
+ FileContents: "file data\n",
+ },
+ }, actual)
+}
- expectedBuildStatements := []BuildStatement{
- {
- Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > python_binary && " +
- "chmod a+x python_binary'",
- InputPaths: []string{"python_binary.zip"},
- OutputPaths: []string{"python_binary"},
- Mnemonic: "TemplateExpand",
- },
- {
- Command: "../bazel_tools/tools/zip/zipper/zipper cC python_binary.zip __main__.py=bazel-out/k8-fastbuild/bin/python_binary.temp " +
- "__init__.py= runfiles/__main__/__init__.py= runfiles/__main__/python_binary.py=python_binary.py && " +
- "../bazel_tools/tools/zip/zipper/zipper x python_binary.zip -d python_binary.runfiles && ln -sf runfiles/__main__ python_binary.runfiles",
- InputPaths: []string{"../bazel_tools/tools/zip/zipper/zipper", "python_binary.py"},
- OutputPaths: []string{"python_binary.zip"},
- Mnemonic: "PythonZipper",
- },
+func TestSourceSymlinkManifest(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "SourceSymlinkManifest",
+ "configurationId": 1,
+ "outputIds": [1],
+ "primaryOutputId": 1,
+ "executionPlatform": "//build/bazel/platforms:linux_x86_64",
+ "fileContents": "symlink target\n"
+ }],
+ "pathFragments": [
+ { "id": 1, "label": "foo.manifest" }]
+}
+`
+ actual, _, err := AqueryBuildStatements([]byte(inputString))
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
}
- assertBuildStatements(t, expectedBuildStatements, actual)
-}
-
-func TestPythonZipperActionNoInput(t *testing.T) {
- const inputString = `
-{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- },{
- "id": 2,
- "pathFragmentId": 2
- }],
- "actions": [{
- "targetId": 1,
- "actionKey": "x",
- "mnemonic": "PythonZipper",
- "configurationId": 1,
- "arguments": ["../bazel_tools/tools/zip/zipper/zipper", "cC", "python_binary.zip", "__main__.py\u003dbazel-out/k8-fastbuild/bin/python_binary.temp", "__init__.py\u003d", "runfiles/__main__/__init__.py\u003d", "runfiles/__main__/python_binary.py\u003dpython_binary.py", "runfiles/bazel_tools/tools/python/py3wrapper.sh\u003dbazel-out/bazel_tools/k8-fastbuild/bin/tools/python/py3wrapper.sh"],
- "outputIds": [2],
- "primaryOutputId": 2
- }],
- "pathFragments": [{
- "id": 1,
- "label": "python_binary"
- },{
- "id": 2,
- "label": "python_binary.zip"
- }]
-}`
- _, _, err := AqueryBuildStatements([]byte(inputString))
- assertError(t, err, `Expect 1+ input and 1 output to python zipper action, got: input [], output ["python_binary.zip"]`)
-}
-
-func TestPythonZipperActionNoOutput(t *testing.T) {
- const inputString = `
-{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- },{
- "id": 2,
- "pathFragmentId": 2
- },{
- "id": 3,
- "pathFragmentId": 3
- },{
- "id": 4,
- "pathFragmentId": 4
- },{
- "id": 5,
- "pathFragmentId": 10
- }],
- "actions": [{
- "targetId": 1,
- "actionKey": "x",
- "mnemonic": "PythonZipper",
- "configurationId": 1,
- "arguments": ["../bazel_tools/tools/zip/zipper/zipper", "cC", "python_binary.zip", "__main__.py\u003dbazel-out/k8-fastbuild/bin/python_binary.temp", "__init__.py\u003d", "runfiles/__main__/__init__.py\u003d", "runfiles/__main__/python_binary.py\u003dpython_binary.py", "runfiles/bazel_tools/tools/python/py3wrapper.sh\u003dbazel-out/bazel_tools/k8-fastbuild/bin/tools/python/py3wrapper.sh"],
- "inputDepSetIds": [1]
- }],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [4, 3, 5]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "python_binary"
- },{
- "id": 2,
- "label": "python_binary.zip"
- },{
- "id": 3,
- "label": "python_binary.py"
- },{
- "id": 9,
- "label": ".."
- }, {
- "id": 8,
- "label": "bazel_tools",
- "parentId": 9
- }, {
- "id": 7,
- "label": "tools",
- "parentId": 8
- }, {
- "id": 6,
- "label": "zip",
- "parentId": 7
- }, {
- "id": 5,
- "label": "zipper",
- "parentId": 6
- }, {
- "id": 4,
- "label": "zipper",
- "parentId": 5
- },{
- "id": 16,
- "label": "bazel-out"
- },{
- "id": 15,
- "label": "bazel_tools",
- "parentId": 16
- }, {
- "id": 14,
- "label": "k8-fastbuild",
- "parentId": 15
- }, {
- "id": 13,
- "label": "bin",
- "parentId": 14
- }, {
- "id": 12,
- "label": "tools",
- "parentId": 13
- }, {
- "id": 11,
- "label": "python",
- "parentId": 12
- }, {
- "id": 10,
- "label": "py3wrapper.sh",
- "parentId": 11
- }]
-}`
- _, _, err := AqueryBuildStatements([]byte(inputString))
- assertError(t, err, `Expect 1+ input and 1 output to python zipper action, got: input ["../bazel_tools/tools/zip/zipper/zipper" "python_binary.py"], output []`)
+ assertBuildStatements(t, []BuildStatement{
+ {
+ OutputPaths: []string{"foo.manifest"},
+ Mnemonic: "SourceSymlinkManifest",
+ },
+ }, actual)
}
func assertError(t *testing.T, err error, expected string) {
@@ -1497,7 +991,7 @@
expectedStatement := expected[i]
if differingField := buildStatementEquals(actualStatement, expectedStatement); differingField != "" {
t.Errorf("%s differs\nunexpected build statement %#v.\nexpected: %#v",
- differingField, actualStatement, expected)
+ differingField, actualStatement, expectedStatement)
return
}
}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index 2b54d45..641984b 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -324,3 +324,69 @@
},
})
}
+
+func TestCcLibraryHeadersExportedStaticLibHeadersReexported(t *testing.T) {
+ runCcLibraryHeadersTestCase(t, bp2buildTestCase{
+ description: "cc_library_headers exported_static_lib_headers is reexported",
+ moduleTypeUnderTest: "cc_library_headers",
+ moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryHeadersPreamble + `
+cc_library_headers {
+ name: "foo_headers",
+ export_static_lib_headers: ["foo_export"],
+ static_libs: ["foo_export", "foo_no_reexport"],
+ bazel_module: { bp2build_available: true },
+}
+` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+ "deps": `[":foo_export"]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryHeadersExportedSharedLibHeadersReexported(t *testing.T) {
+ runCcLibraryHeadersTestCase(t, bp2buildTestCase{
+ description: "cc_library_headers exported_shared_lib_headers is reexported",
+ moduleTypeUnderTest: "cc_library_headers",
+ moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryHeadersPreamble + `
+cc_library_headers {
+ name: "foo_headers",
+ export_shared_lib_headers: ["foo_export"],
+ shared_libs: ["foo_export", "foo_no_reexport"],
+ bazel_module: { bp2build_available: true },
+}
+` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+ "deps": `[":foo_export"]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryHeadersExportedHeaderLibHeadersReexported(t *testing.T) {
+ runCcLibraryHeadersTestCase(t, bp2buildTestCase{
+ description: "cc_library_headers exported_header_lib_headers is reexported",
+ moduleTypeUnderTest: "cc_library_headers",
+ moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryHeadersPreamble + `
+cc_library_headers {
+ name: "foo_headers",
+ export_header_lib_headers: ["foo_export"],
+ header_libs: ["foo_export", "foo_no_reexport"],
+ bazel_module: { bp2build_available: true },
+}
+` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+ "deps": `[":foo_export"]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index be10e86..36c46a4 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -18,6 +18,7 @@
"android/soong/android"
"android/soong/cc"
"android/soong/genrule"
+ "fmt"
"testing"
)
@@ -204,8 +205,8 @@
":whole_static_lib_1",
":whole_static_lib_2",
]`,
- "sdk_version": `"current"`,
- "min_sdk_version": `"29"`,
+ "sdk_version": `"current"`,
+ "min_sdk_version": `"29"`,
}),
},
})
@@ -1489,3 +1490,72 @@
},
})
}
+
+func TestCcLibraryStaticStl(t *testing.T) {
+ testCases := []struct {
+ desc string
+ prop string
+ attr attrNameToString
+ }{
+ {
+ desc: "c++_shared deduped to libc++",
+ prop: `stl: "c++_shared",`,
+ attr: attrNameToString{
+ "stl": `"libc++"`,
+ },
+ },
+ {
+ desc: "libc++ to libc++",
+ prop: `stl: "libc++",`,
+ attr: attrNameToString{
+ "stl": `"libc++"`,
+ },
+ },
+ {
+ desc: "c++_static to libc++_static",
+ prop: `stl: "c++_static",`,
+ attr: attrNameToString{
+ "stl": `"libc++_static"`,
+ },
+ },
+ {
+ desc: "libc++_static to libc++_static",
+ prop: `stl: "libc++_static",`,
+ attr: attrNameToString{
+ "stl": `"libc++_static"`,
+ },
+ },
+ {
+ desc: "system to system",
+ prop: `stl: "system",`,
+ attr: attrNameToString{
+ "stl": `"system"`,
+ },
+ },
+ {
+ desc: "none to none",
+ prop: `stl: "none",`,
+ attr: attrNameToString{
+ "stl": `"none"`,
+ },
+ },
+ {
+ desc: "empty to empty",
+ attr: attrNameToString{},
+ },
+ }
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(*testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ blueprint: fmt.Sprintf(`cc_library_static {
+ name: "foo",
+ include_build_directory: false,
+ %s
+}`, tc.prop),
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo", tc.attr),
+ },
+ })
+ })
+ }
+}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index d891007..fa30d09 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -376,7 +376,8 @@
return
}
if ca.stl == nil {
- ca.stl = stlProps.Stl
+ stl := deduplicateStlInput(*stlProps.Stl)
+ ca.stl = &stl
} else if ca.stl != stlProps.Stl {
ctx.ModuleErrorf("Unsupported conversion: module with different stl for different variants: %s and %s", *ca.stl, stlProps.Stl)
}
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 38f6383..b6d196c 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -3722,6 +3722,25 @@
android.AssertStringDoesContain(t, "min sdk version", cFlags, "-target aarch64-linux-android29")
}
+func TestNonDigitMinSdkVersionInClangTriple(t *testing.T) {
+ bp := `
+ cc_library_shared {
+ name: "libfoo",
+ srcs: ["foo.c"],
+ min_sdk_version: "S",
+ }
+ `
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Platform_version_active_codenames = []string{"UpsideDownCake", "Tiramisu"}
+ }),
+ ).RunTestWithBp(t, bp)
+ ctx := result.TestContext
+ cFlags := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"]
+ android.AssertStringDoesContain(t, "min sdk version", cFlags, "-target aarch64-linux-android31")
+}
+
func TestIncludeDirsExporting(t *testing.T) {
// Trim spaces from the beginning, end and immediately after any newline characters. Leaves
@@ -4076,7 +4095,7 @@
{
name: "assemble",
src: "foo.s",
- expected: combineSlices(baseExpectedFlags, []string{"-D__ASSEMBLY__", "-fdebug-default-version=4"}, expectedIncludes, lastIncludes),
+ expected: combineSlices(baseExpectedFlags, []string{"${config.CommonGlobalAsflags}"}, expectedIncludes, lastIncludes),
},
}
diff --git a/cc/compiler.go b/cc/compiler.go
index cd1d92c..3c904b8 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -457,7 +457,8 @@
if version == "" || version == "current" {
target += strconv.Itoa(android.FutureApiLevelInt)
} else {
- target += version
+ apiLevel := nativeApiLevelOrPanic(ctx, version)
+ target += apiLevel.String()
}
}
@@ -493,11 +494,7 @@
}
}
- flags.Global.AsFlags = append(flags.Global.AsFlags, "-D__ASSEMBLY__")
-
- // TODO(b/235105792): override global -fdebug-default-version=5, it is causing $TMPDIR to
- // end up in the dwarf data for crtend_so.S.
- flags.Global.AsFlags = append(flags.Global.AsFlags, "-fdebug-default-version=4")
+ flags.Global.AsFlags = append(flags.Global.AsFlags, "${config.CommonGlobalAsflags}")
flags.Global.CppFlags = append(flags.Global.CppFlags, tc.Cppflags())
diff --git a/cc/config/global.go b/cc/config/global.go
index b09598a..c5fde55 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -117,6 +117,13 @@
commonGlobalConlyflags = []string{}
+ commonGlobalAsflags = []string{
+ "-D__ASSEMBLY__",
+ // TODO(b/235105792): override global -fdebug-default-version=5, it is causing $TMPDIR to
+ // end up in the dwarf data for crtend_so.S.
+ "-fdebug-default-version=4",
+ }
+
deviceGlobalCflags = []string{
"-ffunction-sections",
"-fdata-sections",
@@ -313,6 +320,7 @@
}
exportedVars.ExportStringListStaticVariable("CommonGlobalConlyflags", commonGlobalConlyflags)
+ exportedVars.ExportStringListStaticVariable("CommonGlobalAsflags", commonGlobalAsflags)
exportedVars.ExportStringListStaticVariable("DeviceGlobalCppflags", deviceGlobalCppflags)
exportedVars.ExportStringListStaticVariable("DeviceGlobalLdflags", deviceGlobalLdflags)
exportedVars.ExportStringListStaticVariable("DeviceGlobalLldflags", deviceGlobalLldflags)
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 77c2523..970d8d1 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -125,6 +125,7 @@
baseAttributes := bp2BuildParseBaseProps(ctx, module)
exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, &baseAttributes.includes)
linkerAttrs := baseAttributes.linkerAttributes
+ (&linkerAttrs.deps).Append(linkerAttrs.dynamicDeps)
attrs := &bazelCcLibraryHeadersAttributes{
Export_includes: exportedIncludes.Includes,
diff --git a/cc/linkable.go b/cc/linkable.go
index c58bfdf..2316d86 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -106,6 +106,9 @@
UnstrippedOutputFile() android.Path
CoverageFiles() android.Paths
+ // CoverageOutputFile returns the output archive of gcno coverage information files.
+ CoverageOutputFile() android.OptionalPath
+
NonCcVariants() bool
SelectedStl() string
@@ -133,6 +136,12 @@
UseSdk() bool
+ // IsNdk returns true if the library is in the configs known NDK list.
+ IsNdk(config android.Config) bool
+
+ // IsStubs returns true if the this is a stubs library.
+ IsStubs() bool
+
// IsLlndk returns true for both LLNDK (public) and LLNDK-private libs.
IsLlndk() bool
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 92987f7..86472a2 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -430,7 +430,7 @@
}
// Enable Memtag for all components in the include paths (for Aarch64 only)
- if ctx.Arch().ArchType == android.Arm64 {
+ if ctx.Arch().ArchType == android.Arm64 && ctx.toolchain().Bionic() {
if ctx.Config().MemtagHeapSyncEnabledForPath(ctx.ModuleDir()) {
if s.Memtag_heap == nil {
s.Memtag_heap = proptools.BoolPtr(true)
@@ -460,17 +460,17 @@
}
// HWASan requires AArch64 hardware feature (top-byte-ignore).
- if ctx.Arch().ArchType != android.Arm64 {
+ if ctx.Arch().ArchType != android.Arm64 || !ctx.toolchain().Bionic() {
s.Hwaddress = nil
}
// SCS is only implemented on AArch64.
- if ctx.Arch().ArchType != android.Arm64 {
+ if ctx.Arch().ArchType != android.Arm64 || !ctx.toolchain().Bionic() {
s.Scs = nil
}
// Memtag_heap is only implemented on AArch64.
- if ctx.Arch().ArchType != android.Arm64 {
+ if ctx.Arch().ArchType != android.Arm64 || !ctx.toolchain().Bionic() {
s.Memtag_heap = nil
}
@@ -710,8 +710,13 @@
// Host sanitizers only link symbols in the final executable, so
// there will always be undefined symbols in intermediate libraries.
_, flags.Global.LdFlags = removeFromList("-Wl,--no-undefined", flags.Global.LdFlags)
+ }
- // non-Bionic toolchain prebuilts are missing UBSan's vptr and function san
+ if !ctx.toolchain().Bionic() {
+ // non-Bionic toolchain prebuilts are missing UBSan's vptr and function san.
+ // Musl toolchain prebuilts have vptr and function sanitizers, but enabling them
+ // implicitly enables RTTI which causes RTTI mismatch issues with dependencies.
+
flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=vptr,function")
}
diff --git a/cc/stl.go b/cc/stl.go
index 0f2a878..85a06da 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -25,6 +25,16 @@
return family
}
+func deduplicateStlInput(stl string) string {
+ switch stl {
+ case "c++_shared":
+ return "libc++"
+ case "c++_static":
+ return "libc++_static"
+ }
+ return stl
+}
+
func getNdkStlFamilyAndLinkType(m LinkableInterface) (string, string) {
stl := m.SelectedStl()
switch stl {
@@ -66,18 +76,18 @@
} else if ctx.header() {
s = "none"
}
+ if s == "none" {
+ return ""
+ }
+ s = deduplicateStlInput(s)
if ctx.useSdk() && ctx.Device() {
switch s {
case "", "system":
return "ndk_system"
- case "c++_shared", "c++_static":
- return "ndk_lib" + s
case "libc++":
return "ndk_libc++_shared"
case "libc++_static":
return "ndk_libc++_static"
- case "none":
- return ""
default:
ctx.ModuleErrorf("stl: %q is not a supported STL with sdk_version set", s)
return ""
@@ -87,8 +97,6 @@
case "libc++", "libc++_static", "":
// Only use static libc++ for Windows.
return "libc++_static"
- case "none":
- return ""
default:
ctx.ModuleErrorf("stl: %q is not a supported STL for windows", s)
return ""
@@ -97,12 +105,6 @@
switch s {
case "libc++", "libc++_static":
return s
- case "c++_shared":
- return "libc++"
- case "c++_static":
- return "libc++_static"
- case "none":
- return ""
case "", "system":
if ctx.static() {
return "libc++_static"
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index a03a86a..16f994d 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -221,6 +221,7 @@
}
defer build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, files...)
defer met.Dump(soongMetricsFile)
+ defer build.CheckProdCreds(buildCtx, config)
}
// Read the time at the starting point.
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index de139c4..d8011d6 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -394,10 +394,14 @@
if !android.PrefixInList(preoptFlags, "--compiler-filter=") {
var compilerFilter string
if systemServerJars.ContainsJar(module.Name) {
- // Jars of system server, use the product option if it is set, speed otherwise.
if global.SystemServerCompilerFilter != "" {
+ // Use the product option if it is set.
compilerFilter = global.SystemServerCompilerFilter
+ } else if profile != nil {
+ // Use "speed-profile" for system server jars that have a profile.
+ compilerFilter = "speed-profile"
} else {
+ // Use "speed" for system server jars that do not have a profile.
compilerFilter = "speed"
}
} else if contains(global.SpeedApps, module.Name) || contains(global.SystemServerApps, module.Name) {
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 2a80563..b796877 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -590,6 +590,18 @@
}
func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // Allowlist genrule to use depfile until we have a solution to remove it.
+ // TODO(b/235582219): Remove allowlist for genrule
+ if ctx.ModuleType() == "gensrcs" &&
+ !ctx.DeviceConfig().BuildBrokenDepfile() &&
+ Bool(g.properties.Depfile) {
+ ctx.PropertyErrorf(
+ "depfile",
+ "Deprecated to ensure the module type is convertible to Bazel. "+
+ "Try specifying the dependencies explicitly so that there is no need to use depfile. "+
+ "If not possible, the escape hatch is to use BUILD_BROKEN_DEPFILE to bypass the error.")
+ }
+
g.generateCommonBuildActions(ctx)
// For <= 6 outputs, just embed those directly in the users. Right now, that covers >90% of
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 1b5cef2..b9be1f7 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -15,6 +15,7 @@
package genrule
import (
+ "fmt"
"os"
"regexp"
"testing"
@@ -626,6 +627,73 @@
}
}
+func TestGensrcsBuildBrokenDepfile(t *testing.T) {
+ tests := []struct {
+ name string
+ prop string
+ BuildBrokenDepfile *bool
+ err string
+ }{
+ {
+ name: `error when BuildBrokenDepfile is set to false`,
+ prop: `
+ depfile: true,
+ cmd: "cat $(in) > $(out) && cat $(depfile)",
+ `,
+ BuildBrokenDepfile: proptools.BoolPtr(false),
+ err: "depfile: Deprecated to ensure the module type is convertible to Bazel",
+ },
+ {
+ name: `error when BuildBrokenDepfile is not set`,
+ prop: `
+ depfile: true,
+ cmd: "cat $(in) > $(out) && cat $(depfile)",
+ `,
+ err: "depfile: Deprecated to ensure the module type is convertible to Bazel.",
+ },
+ {
+ name: `no error when BuildBrokenDepfile is explicitly set to true`,
+ prop: `
+ depfile: true,
+ cmd: "cat $(in) > $(out) && cat $(depfile)",
+ `,
+ BuildBrokenDepfile: proptools.BoolPtr(true),
+ },
+ {
+ name: `no error if depfile is not set`,
+ prop: `
+ cmd: "cat $(in) > $(out)",
+ `,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ bp := fmt.Sprintf(`
+ gensrcs {
+ name: "foo",
+ srcs: ["data.txt"],
+ %s
+ }`, test.prop)
+
+ var expectedErrors []string
+ if test.err != "" {
+ expectedErrors = append(expectedErrors, test.err)
+ }
+ android.GroupFixturePreparers(
+ prepareForGenRuleTest,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ if test.BuildBrokenDepfile != nil {
+ variables.BuildBrokenDepfile = test.BuildBrokenDepfile
+ }
+ }),
+ ).
+ ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)).
+ RunTestWithBp(t, bp)
+ })
+
+ }
+}
+
func TestGenruleDefaults(t *testing.T) {
bp := `
genrule_defaults {
diff --git a/java/app.go b/java/app.go
index 8ff5d91..23a9816 100755
--- a/java/app.go
+++ b/java/app.go
@@ -740,7 +740,7 @@
tag := ctx.OtherModuleDependencyTag(module)
if IsJniDepTag(tag) || cc.IsSharedDepTag(tag) {
- if dep, ok := module.(*cc.Module); ok {
+ if dep, ok := module.(cc.LinkableInterface); ok {
if dep.IsNdk(ctx.Config()) || dep.IsStubs() {
return false
}
diff --git a/java/base.go b/java/base.go
index b76dcc9..a391f64 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1425,17 +1425,18 @@
j.implementationAndResourcesJar = implementationAndResourcesJar
// Enable dex compilation for the APEX variants, unless it is disabled explicitly
+ compileDex := j.dexProperties.Compile_dex
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if j.DirectlyInAnyApex() && !apexInfo.IsForPlatform() {
- if j.dexProperties.Compile_dex == nil {
- j.dexProperties.Compile_dex = proptools.BoolPtr(true)
+ if compileDex == nil {
+ compileDex = proptools.BoolPtr(true)
}
if j.deviceProperties.Hostdex == nil {
j.deviceProperties.Hostdex = proptools.BoolPtr(true)
}
}
- if ctx.Device() && (Bool(j.properties.Installable) || Bool(j.dexProperties.Compile_dex)) {
+ if ctx.Device() && (Bool(j.properties.Installable) || Bool(compileDex)) {
if j.hasCode(ctx) {
if j.shouldInstrumentStatic(ctx) {
j.dexer.extraProguardFlagFiles = append(j.dexer.extraProguardFlagFiles,
@@ -1491,11 +1492,30 @@
}
if ctx.Device() {
- lintSDKVersion := func(sdkSpec android.SdkSpec) android.ApiLevel {
+ lintSDKVersion := func(sdkSpec android.SdkSpec) int {
if v := sdkSpec.ApiLevel; !v.IsPreview() {
- return v
+ return v.FinalInt()
} else {
- return ctx.Config().DefaultAppTargetSdk(ctx)
+ // When running metalava, we pass --version-codename. When that value
+ // is not REL, metalava will add 1 to the --current-version argument.
+ // On old branches, PLATFORM_SDK_VERSION is the latest version (for that
+ // branch) and the codename is REL, except potentially on the most
+ // recent non-master branch. On that branch, it goes through two other
+ // phases before it gets to the phase previously described:
+ // - PLATFORM_SDK_VERSION has not been updated yet, and the codename
+ // is not rel. This happens for most of the internal branch's life
+ // while the branch has been cut but is still under active development.
+ // - PLATFORM_SDK_VERSION has been set, but the codename is still not
+ // REL. This happens briefly during the release process. During this
+ // state the code to add --current-version is commented out, and then
+ // that commenting out is reverted after the codename is set to REL.
+ // On the master branch, the PLATFORM_SDK_VERSION always represents a
+ // prior version and the codename is always non-REL.
+ //
+ // We need to add one here to match metalava adding 1. Technically
+ // this means that in the state described in the second bullet point
+ // above, this number is 1 higher than it should be.
+ return ctx.Config().PlatformSdkVersion().FinalInt() + 1
}
}
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 0591012..f08b64b 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -32,12 +32,7 @@
func init() {
registerBootclasspathFragmentBuildComponents(android.InitRegistrationContext)
- android.RegisterSdkMemberType(&bootclasspathFragmentMemberType{
- SdkMemberTypeBase: android.SdkMemberTypeBase{
- PropertyName: "bootclasspath_fragments",
- SupportsSdk: true,
- },
- })
+ android.RegisterSdkMemberType(BootclasspathFragmentSdkMemberType)
}
func registerBootclasspathFragmentBuildComponents(ctx android.RegistrationContext) {
@@ -46,6 +41,15 @@
ctx.RegisterModuleType("prebuilt_bootclasspath_fragment", prebuiltBootclasspathFragmentFactory)
}
+// BootclasspathFragmentSdkMemberType is the member type used to add bootclasspath_fragments to
+// the SDK snapshot. It is exported for use by apex.
+var BootclasspathFragmentSdkMemberType = &bootclasspathFragmentMemberType{
+ SdkMemberTypeBase: android.SdkMemberTypeBase{
+ PropertyName: "bootclasspath_fragments",
+ SupportsSdk: true,
+ },
+}
+
type bootclasspathFragmentContentDependencyTag struct {
blueprint.BaseDependencyTag
}
diff --git a/java/fuzz.go b/java/fuzz.go
index b306991..d0f369f 100644
--- a/java/fuzz.go
+++ b/java/fuzz.go
@@ -171,6 +171,10 @@
return
}
+ if javaFuzzModule.Target().HostCross {
+ return
+ }
+
fuzzModuleValidator := fuzz.FuzzModule{
javaFuzzModule.ModuleBase,
javaFuzzModule.DefaultableModuleBase,
diff --git a/java/java.go b/java/java.go
index c2a7829..6e05159 100644
--- a/java/java.go
+++ b/java/java.go
@@ -164,6 +164,9 @@
android.SdkMemberTypeBase{
PropertyName: "java_systemserver_libs",
SupportsSdk: true,
+
+ // This was only added in Tiramisu.
+ SupportedBuildReleaseSpecification: "Tiramisu+",
},
func(ctx android.SdkMemberContext, j *Library) android.Path {
// Java systemserver libs are only provided in the SDK to provide access to their dex
diff --git a/java/lint.go b/java/lint.go
index 22c9ec4..e276345 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -17,6 +17,7 @@
import (
"fmt"
"sort"
+ "strconv"
"strings"
"github.com/google/blueprint/proptools"
@@ -75,9 +76,9 @@
extraLintCheckJars android.Paths
test bool
library bool
- minSdkVersion android.ApiLevel
- targetSdkVersion android.ApiLevel
- compileSdkVersion android.ApiLevel
+ minSdkVersion int
+ targetSdkVersion int
+ compileSdkVersion int
compileSdkKind android.SdkKind
javaLanguageLevel string
kotlinLanguageLevel string
@@ -299,8 +300,8 @@
Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
- Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
- l.minSdkVersion.String(), l.targetSdkVersion.String()).
+ Textf(`echo " <uses-sdk android:minSdkVersion='%d' android:targetSdkVersion='%d'/>" &&`,
+ l.minSdkVersion, l.targetSdkVersion).
Text(`echo "</manifest>"`).
Text(") >").Output(manifestPath)
@@ -325,7 +326,7 @@
return
}
- if l.minSdkVersion.CompareTo(l.compileSdkVersion) == -1 {
+ if l.minSdkVersion != l.compileSdkVersion {
l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
_, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
if len(filtered) != 0 {
@@ -427,7 +428,7 @@
FlagWithOutput("--html ", html).
FlagWithOutput("--text ", text).
FlagWithOutput("--xml ", xml).
- FlagWithArg("--compile-sdk-version ", l.compileSdkVersion.String()).
+ FlagWithArg("--compile-sdk-version ", strconv.Itoa(l.compileSdkVersion)).
FlagWithArg("--java-language-level ", l.javaLanguageLevel).
FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index fa61ea6..a2cd261 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -24,12 +24,7 @@
func init() {
registerSystemserverClasspathBuildComponents(android.InitRegistrationContext)
- android.RegisterSdkMemberType(&systemServerClasspathFragmentMemberType{
- SdkMemberTypeBase: android.SdkMemberTypeBase{
- PropertyName: "systemserverclasspath_fragments",
- SupportsSdk: true,
- },
- })
+ android.RegisterSdkMemberType(SystemServerClasspathFragmentSdkMemberType)
}
func registerSystemserverClasspathBuildComponents(ctx android.RegistrationContext) {
@@ -38,6 +33,17 @@
ctx.RegisterModuleType("prebuilt_systemserverclasspath_fragment", prebuiltSystemServerClasspathModuleFactory)
}
+var SystemServerClasspathFragmentSdkMemberType = &systemServerClasspathFragmentMemberType{
+ SdkMemberTypeBase: android.SdkMemberTypeBase{
+ PropertyName: "systemserverclasspath_fragments",
+ SupportsSdk: true,
+
+ // Support for adding systemserverclasspath_fragments to the sdk snapshot was only added in
+ // Tiramisu.
+ SupportedBuildReleaseSpecification: "Tiramisu+",
+ },
+}
+
type platformSystemServerClasspathModule struct {
android.ModuleBase
diff --git a/rust/bindgen.go b/rust/bindgen.go
index b4626a0..4d723d6 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -41,10 +41,25 @@
//TODO(b/160803703) Use a prebuilt bindgen instead of the built bindgen.
_ = pctx.HostBinToolVariable("bindgenCmd", "bindgen")
+ _ = pctx.VariableFunc("bindgenHostPrebuiltTag", func(ctx android.PackageVarContext) string {
+ if ctx.Config().UseHostMusl() {
+ // This is a hack to use the glibc bindgen binary until we have a musl version checked in.
+ return "linux-x86"
+ } else {
+ return "${config.HostPrebuiltTag}"
+ }
+ })
+ _ = pctx.VariableFunc("bindgenClangLibdir", func(ctx android.PackageVarContext) string {
+ if ctx.Config().UseHostMusl() {
+ return "musl/lib64/"
+ } else {
+ return "lib64/"
+ }
+ })
_ = pctx.SourcePathVariable("bindgenClang",
- "${cc_config.ClangBase}/${config.HostPrebuiltTag}/${bindgenClangVersion}/bin/clang")
+ "${cc_config.ClangBase}/${bindgenHostPrebuiltTag}/${bindgenClangVersion}/bin/clang")
_ = pctx.SourcePathVariable("bindgenLibClang",
- "${cc_config.ClangBase}/${config.HostPrebuiltTag}/${bindgenClangVersion}/lib64/")
+ "${cc_config.ClangBase}/${bindgenHostPrebuiltTag}/${bindgenClangVersion}/${bindgenClangLibdir}")
//TODO(ivanlozano) Switch this to RuleBuilder
bindgen = pctx.AndroidStaticRule("bindgen",
diff --git a/rust/compiler.go b/rust/compiler.go
index bcd58c8..bf6a488 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -371,8 +371,9 @@
if !Bool(compiler.Properties.No_stdlibs) {
for _, stdlib := range config.Stdlibs {
- // If we're building for the build host, use the prebuilt stdlibs
- if ctx.Target().Os == android.Linux || ctx.Target().Os == android.Darwin {
+ // If we're building for the build host, use the prebuilt stdlibs, unless the host
+ // is linux_bionic which doesn't have prebuilts.
+ if ctx.Host() && !ctx.Target().HostCross && ctx.Target().Os != android.LinuxBionic {
stdlib = "prebuilt_" + stdlib
}
deps.Stdlibs = append(deps.Stdlibs, stdlib)
diff --git a/rust/config/Android.bp b/rust/config/Android.bp
index 7757c79..ba40cb0 100644
--- a/rust/config/Android.bp
+++ b/rust/config/Android.bp
@@ -11,6 +11,7 @@
],
srcs: [
"arm_device.go",
+ "arm_linux_host.go",
"arm64_device.go",
"global.go",
"lints.go",
diff --git a/rust/config/arm_linux_host.go b/rust/config/arm_linux_host.go
new file mode 100644
index 0000000..22bdaee
--- /dev/null
+++ b/rust/config/arm_linux_host.go
@@ -0,0 +1,147 @@
+// Copyright 2022 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 config
+
+import (
+ "strings"
+
+ "android/soong/android"
+)
+
+var (
+ linuxArmRustflags = []string{}
+ linuxArmLinkflags = []string{}
+ linuxArm64Rustflags = []string{}
+ linuxArm64Linkflags = []string{}
+)
+
+func init() {
+ registerToolchainFactory(android.LinuxMusl, android.Arm64, linuxMuslArm64ToolchainFactory)
+ registerToolchainFactory(android.LinuxMusl, android.Arm, linuxMuslArmToolchainFactory)
+
+ pctx.StaticVariable("LinuxToolchainArmRustFlags", strings.Join(linuxArmRustflags, " "))
+ pctx.StaticVariable("LinuxToolchainArmLinkFlags", strings.Join(linuxArmLinkflags, " "))
+ pctx.StaticVariable("LinuxToolchainArm64RustFlags", strings.Join(linuxArm64Rustflags, " "))
+ pctx.StaticVariable("LinuxToolchainArm64LinkFlags", strings.Join(linuxArm64Linkflags, " "))
+}
+
+// Base 64-bit linux rust toolchain
+type toolchainLinuxArm64 struct {
+ toolchain64Bit
+}
+
+func (toolchainLinuxArm64) Supported() bool {
+ return true
+}
+
+func (toolchainLinuxArm64) Bionic() bool {
+ return false
+}
+
+func (t *toolchainLinuxArm64) Name() string {
+ return "arm64"
+}
+
+func (t *toolchainLinuxArm64) ToolchainLinkFlags() string {
+ // Prepend the lld flags from cc_config so we stay in sync with cc
+ return "${cc_config.LinuxLldflags} ${cc_config.LinuxArm64Lldflags} " +
+ "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainArm64LinkFlags}"
+}
+
+func (t *toolchainLinuxArm64) ToolchainRustFlags() string {
+ return "${config.LinuxToolchainRustFlags} ${config.LinuxToolchainArm64RustFlags}"
+}
+
+// Specialization of the 64-bit linux rust toolchain for musl. Adds the musl rust triple and
+// linker flags to avoid using the host sysroot.
+type toolchainLinuxMuslArm64 struct {
+ toolchainLinuxArm64
+}
+
+func (t *toolchainLinuxMuslArm64) RustTriple() string {
+ return "aarch64-unknown-linux-musl"
+}
+
+func (t *toolchainLinuxMuslArm64) ToolchainLinkFlags() string {
+ return t.toolchainLinuxArm64.ToolchainLinkFlags() + " " + "${config.LinuxMuslToolchainLinkFlags}"
+}
+
+func (t *toolchainLinuxMuslArm64) ToolchainRustFlags() string {
+ return t.toolchainLinuxArm64.ToolchainRustFlags() + " " + "${config.LinuxMuslToolchainRustFlags}"
+}
+
+func linuxMuslArm64ToolchainFactory(arch android.Arch) Toolchain {
+ return toolchainLinuxMuslArm64Singleton
+}
+
+// Base 32-bit linux rust toolchain
+type toolchainLinuxArm struct {
+ toolchain32Bit
+}
+
+func (toolchainLinuxArm) Supported() bool {
+ return true
+}
+
+func (toolchainLinuxArm) Bionic() bool {
+ return false
+}
+
+func (t *toolchainLinuxArm) Name() string {
+ return "arm"
+}
+
+func (toolchainLinuxArm) LibclangRuntimeLibraryArch() string {
+ return "arm"
+}
+
+func (toolchainLinuxArm64) LibclangRuntimeLibraryArch() string {
+ return "arm64"
+}
+
+func (t *toolchainLinuxArm) ToolchainLinkFlags() string {
+ // Prepend the lld flags from cc_config so we stay in sync with cc
+ return "${cc_config.LinuxLldflags} ${cc_config.LinuxArmLldflags} " +
+ "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainArmLinkFlags}"
+}
+
+func (t *toolchainLinuxArm) ToolchainRustFlags() string {
+ return "${config.LinuxToolchainRustFlags} ${config.LinuxToolchainArmRustFlags}"
+}
+
+// Specialization of the 32-bit linux rust toolchain for musl. Adds the musl rust triple and
+// linker flags to avoid using the host sysroot.
+type toolchainLinuxMuslArm struct {
+ toolchainLinuxArm
+}
+
+func (t *toolchainLinuxMuslArm) RustTriple() string {
+ return "arm-unknown-linux-musleabihf"
+}
+
+func (t *toolchainLinuxMuslArm) ToolchainLinkFlags() string {
+ return t.toolchainLinuxArm.ToolchainLinkFlags() + " " + "${config.LinuxMuslToolchainLinkFlags}"
+}
+
+func (t *toolchainLinuxMuslArm) ToolchainRustFlags() string {
+ return t.toolchainLinuxArm.ToolchainRustFlags() + " " + "${config.LinuxMuslToolchainRustFlags}"
+}
+
+func linuxMuslArmToolchainFactory(arch android.Arch) Toolchain {
+ return toolchainLinuxMuslArmSingleton
+}
+
+var toolchainLinuxMuslArm64Singleton Toolchain = &toolchainLinuxMuslArm64{}
+var toolchainLinuxMuslArmSingleton Toolchain = &toolchainLinuxMuslArm{}
diff --git a/rust/config/global.go b/rust/config/global.go
index e9751fd..3ef0ecb 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -78,7 +78,13 @@
func init() {
pctx.SourcePathVariable("RustDefaultBase", RustDefaultBase)
- pctx.VariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS)
+ pctx.VariableConfigMethod("HostPrebuiltTag", func(config android.Config) string {
+ if config.UseHostMusl() {
+ return "linux-musl-x86"
+ } else {
+ return config.PrebuiltOS()
+ }
+ })
pctx.VariableFunc("RustBase", func(ctx android.PackageVarContext) string {
if override := ctx.Config().Getenv("RUST_PREBUILTS_BASE"); override != "" {
diff --git a/rust/rust.go b/rust/rust.go
index 48419eb..d5d4929 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -695,6 +695,19 @@
panic(fmt.Errorf("CoverageFiles called on non-library module: %q", mod.BaseModuleName()))
}
+// Rust does not produce gcno files, and therefore does not produce a coverage archive.
+func (mod *Module) CoverageOutputFile() android.OptionalPath {
+ return android.OptionalPath{}
+}
+
+func (mod *Module) IsNdk(config android.Config) bool {
+ return false
+}
+
+func (mod *Module) IsStubs() bool {
+ return false
+}
+
func (mod *Module) installable(apexInfo android.ApexInfo) bool {
if !proptools.BoolDefault(mod.Installable(), mod.EverInstallable()) {
return false
diff --git a/rust/sanitize.go b/rust/sanitize.go
index 536fcbd..a3c5cb5 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -174,7 +174,7 @@
}
// Enable Memtag for all components in the include paths (for Aarch64 only)
- if ctx.Arch().ArchType == android.Arm64 {
+ if ctx.Arch().ArchType == android.Arm64 && ctx.Os().Bionic() {
if ctx.Config().MemtagHeapSyncEnabledForPath(ctx.ModuleDir()) {
if s.Memtag_heap == nil {
s.Memtag_heap = proptools.BoolPtr(true)
@@ -200,7 +200,7 @@
}
// HWASan requires AArch64 hardware feature (top-byte-ignore).
- if ctx.Arch().ArchType != android.Arm64 {
+ if ctx.Arch().ArchType != android.Arm64 || !ctx.Os().Bionic() {
s.Hwaddress = nil
}
@@ -215,7 +215,7 @@
}
// Memtag_heap is only implemented on AArch64.
- if ctx.Arch().ArchType != android.Arm64 {
+ if ctx.Arch().ArchType != android.Arm64 || !ctx.Os().Bionic() {
s.Memtag_heap = nil
}
@@ -234,7 +234,7 @@
}
if Bool(sanitize.Properties.Sanitize.Fuzzer) {
flags.RustFlags = append(flags.RustFlags, fuzzerFlags...)
- if ctx.Arch().ArchType == android.Arm64 {
+ if ctx.Arch().ArchType == android.Arm64 && ctx.Os().Bionic() {
flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
} else {
flags.RustFlags = append(flags.RustFlags, asanFlags...)
@@ -282,13 +282,13 @@
var deps []string
if mod.IsSanitizerEnabled(cc.Asan) ||
- (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType != android.Arm64) {
+ (mod.IsSanitizerEnabled(cc.Fuzzer) && (mctx.Arch().ArchType != android.Arm64 || !mctx.Os().Bionic())) {
variations = append(variations,
blueprint.Variation{Mutator: "link", Variation: "shared"})
depTag = cc.SharedDepTag()
deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")}
} else if mod.IsSanitizerEnabled(cc.Hwasan) ||
- (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType == android.Arm64) {
+ (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType == android.Arm64 && mctx.Os().Bionic()) {
// TODO(b/204776996): HWASan for static Rust binaries isn't supported yet.
if binary, ok := mod.compiler.(binaryInterface); ok {
if binary.staticallyLinked() {
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index 93ad172..13ddbe7 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -190,7 +190,7 @@
android.AssertStringDoesContain(t, "boot jars package check", command, expectedCommandArgs)
}
-func TestSnapshotWithBootClasspathFragment_Contents(t *testing.T) {
+func testSnapshotWithBootClasspathFragment_Contents(t *testing.T, sdk string, copyRules string) {
result := android.GroupFixturePreparers(
prepareForSdkTestWithJava,
java.PrepareForTestWithJavaDefaultModules,
@@ -202,19 +202,7 @@
// Add a platform_bootclasspath that depends on the fragment.
fixtureAddPlatformBootclasspathForBootclasspathFragment("myapex", "mybootclasspathfragment"),
- android.FixtureWithRootAndroidBp(`
- sdk {
- name: "mysdk",
- bootclasspath_fragments: ["mybootclasspathfragment"],
- java_sdk_libs: [
- // This is not strictly needed as it should be automatically added to the sdk_snapshot as
- // a java_sdk_libs module because it is used in the mybootclasspathfragment's
- // api.stub_libs property. However, it is specified here to ensure that duplicates are
- // correctly deduped.
- "mysdklibrary",
- ],
- }
-
+ android.FixtureWithRootAndroidBp(sdk+`
apex {
name: "myapex",
key: "myapex.key",
@@ -373,24 +361,7 @@
},
}
`),
- checkAllCopyRules(`
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
-.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
-.intermediates/myothersdklibrary.stubs/android_common/javac/myothersdklibrary.stubs.jar -> sdk_library/public/myothersdklibrary-stubs.jar
-.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
-.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_removed.txt -> sdk_library/public/myothersdklibrary-removed.txt
-.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
-.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
-.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
-.intermediates/mycoreplatform.stubs/android_common/javac/mycoreplatform.stubs.jar -> sdk_library/public/mycoreplatform-stubs.jar
-.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_api.txt -> sdk_library/public/mycoreplatform.txt
-.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_removed.txt -> sdk_library/public/mycoreplatform-removed.txt
-`),
+ checkAllCopyRules(copyRules),
snapshotTestPreparer(checkSnapshotWithoutSource, preparerForSnapshot),
snapshotTestChecker(checkSnapshotWithoutSource, func(t *testing.T, result *android.TestResult) {
module := result.ModuleForTests("platform-bootclasspath", "android_common")
@@ -427,6 +398,89 @@
)
}
+func TestSnapshotWithBootClasspathFragment_Contents(t *testing.T) {
+ t.Run("added-directly", func(t *testing.T) {
+ testSnapshotWithBootClasspathFragment_Contents(t, `
+ sdk {
+ name: "mysdk",
+ bootclasspath_fragments: ["mybootclasspathfragment"],
+ java_sdk_libs: [
+ // This is not strictly needed as it should be automatically added to the sdk_snapshot as
+ // a java_sdk_libs module because it is used in the mybootclasspathfragment's
+ // api.stub_libs property. However, it is specified here to ensure that duplicates are
+ // correctly deduped.
+ "mysdklibrary",
+ ],
+ }
+ `, `
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
+.intermediates/myothersdklibrary.stubs/android_common/javac/myothersdklibrary.stubs.jar -> sdk_library/public/myothersdklibrary-stubs.jar
+.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
+.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_removed.txt -> sdk_library/public/myothersdklibrary-removed.txt
+.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
+.intermediates/mycoreplatform.stubs/android_common/javac/mycoreplatform.stubs.jar -> sdk_library/public/mycoreplatform-stubs.jar
+.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_api.txt -> sdk_library/public/mycoreplatform.txt
+.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_removed.txt -> sdk_library/public/mycoreplatform-removed.txt
+`)
+ })
+
+ copyBootclasspathFragmentFromApexVariantRules := `
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/index.csv -> hiddenapi/index.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
+.intermediates/myothersdklibrary.stubs/android_common/javac/myothersdklibrary.stubs.jar -> sdk_library/public/myothersdklibrary-stubs.jar
+.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
+.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_removed.txt -> sdk_library/public/myothersdklibrary-removed.txt
+.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
+.intermediates/mycoreplatform.stubs/android_common/javac/mycoreplatform.stubs.jar -> sdk_library/public/mycoreplatform-stubs.jar
+.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_api.txt -> sdk_library/public/mycoreplatform.txt
+.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_removed.txt -> sdk_library/public/mycoreplatform-removed.txt
+`
+ t.Run("added-via-apex", func(t *testing.T) {
+ testSnapshotWithBootClasspathFragment_Contents(t, `
+ sdk {
+ name: "mysdk",
+ apexes: ["myapex"],
+ }
+ `, copyBootclasspathFragmentFromApexVariantRules)
+ })
+
+ t.Run("added-directly-and-indirectly", func(t *testing.T) {
+ testSnapshotWithBootClasspathFragment_Contents(t, `
+ sdk {
+ name: "mysdk",
+ apexes: ["myapex"],
+ // This is not strictly needed as it should be automatically added to the sdk_snapshot as
+ // a bootclasspath_fragments module because it is used in the myapex's
+ // bootclasspath_fragments property. However, it is specified here to ensure that duplicates
+ // are correctly deduped.
+ bootclasspath_fragments: ["mybootclasspathfragment"],
+ java_sdk_libs: [
+ // This is not strictly needed as it should be automatically added to the sdk_snapshot as
+ // a java_sdk_libs module because it is used in the mybootclasspathfragment's
+ // api.stub_libs property. However, it is specified here to ensure that duplicates are
+ // correctly deduped.
+ "mysdklibrary",
+ ],
+ }
+ `, copyBootclasspathFragmentFromApexVariantRules)
+ })
+}
+
// TestSnapshotWithBootClasspathFragment_Fragments makes sure that the fragments property of a
// bootclasspath_fragment is correctly output to the sdk snapshot.
func TestSnapshotWithBootClasspathFragment_Fragments(t *testing.T) {
diff --git a/sdk/systemserverclasspath_fragment_sdk_test.go b/sdk/systemserverclasspath_fragment_sdk_test.go
index 01692a3..1ac405d 100644
--- a/sdk/systemserverclasspath_fragment_sdk_test.go
+++ b/sdk/systemserverclasspath_fragment_sdk_test.go
@@ -22,28 +22,21 @@
"android/soong/java"
)
-func TestSnapshotWithSystemServerClasspathFragment(t *testing.T) {
+func testSnapshotWithSystemServerClasspathFragment(t *testing.T, sdk string, targetBuildRelease string, expectedSdkSnapshot string) {
result := android.GroupFixturePreparers(
prepareForSdkTestWithJava,
java.PrepareForTestWithJavaDefaultModules,
java.PrepareForTestWithJavaSdkLibraryFiles,
java.FixtureWithLastReleaseApis("mysdklibrary"),
dexpreopt.FixtureSetApexSystemServerJars("myapex:mylib", "myapex:mysdklibrary"),
+ android.FixtureModifyEnv(func(env map[string]string) {
+ if targetBuildRelease != "latest" {
+ env["SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE"] = targetBuildRelease
+ }
+ }),
prepareForSdkTestWithApex,
- android.FixtureWithRootAndroidBp(`
- sdk {
- name: "mysdk",
- systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
- java_sdk_libs: [
- // This is not strictly needed as it should be automatically added to the sdk_snapshot as
- // a java_sdk_libs module because it is used in the mysystemserverclasspathfragment's
- // contents property. However, it is specified here to ensure that duplicates are
- // correctly deduped.
- "mysdklibrary",
- ],
- }
-
+ android.FixtureWithRootAndroidBp(sdk+`
apex {
name: "myapex",
key: "myapex.key",
@@ -83,7 +76,27 @@
).RunTest(t)
CheckSnapshot(t, result, "mysdk", "",
- checkAndroidBpContents(`
+ checkAndroidBpContents(expectedSdkSnapshot),
+ )
+}
+
+func TestSnapshotWithSystemServerClasspathFragment(t *testing.T) {
+
+ commonSdk := `
+sdk {
+ name: "mysdk",
+ systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
+ java_sdk_libs: [
+ // This is not strictly needed as it should be automatically added to the sdk_snapshot as
+ // a java_sdk_libs module because it is used in the mysystemserverclasspathfragment's
+ // contents property. However, it is specified here to ensure that duplicates are
+ // correctly deduped.
+ "mysdklibrary",
+ ],
+}
+ `
+
+ expectedLatestSnapshot := `
// This is auto-generated. DO NOT EDIT.
java_sdk_library_import {
@@ -120,6 +133,80 @@
"mysdklibrary",
],
}
-`),
- )
+`
+
+ t.Run("target-s", func(t *testing.T) {
+ testSnapshotWithSystemServerClasspathFragment(t, commonSdk, "S", `
+// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+ name: "mysdklibrary",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["myapex"],
+ shared_library: false,
+ 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",
+ },
+}
+`)
+ })
+
+ t.Run("target-t", func(t *testing.T) {
+ testSnapshotWithSystemServerClasspathFragment(t, commonSdk, "Tiramisu", `
+// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+ name: "mysdklibrary",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["myapex"],
+ shared_library: false,
+ 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"],
+ permitted_packages: ["mylib"],
+}
+
+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)
+ })
+
+ t.Run("added-via-apex", func(t *testing.T) {
+ testSnapshotWithSystemServerClasspathFragment(t, `
+ sdk {
+ name: "mysdk",
+ apexes: ["myapex"],
+ }
+ `, `latest`, expectedLatestSnapshot)
+ })
}
diff --git a/sdk/update.go b/sdk/update.go
index 457828b..b9ef3d0 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -239,7 +239,7 @@
// Finally, the member type slices are concatenated together to form a single slice. The order in
// which they are concatenated is the order in which the member types were registered in the
// android.SdkMemberTypesRegistry.
-func (s *sdk) groupMemberVariantsByMemberThenType(ctx android.ModuleContext, memberVariantDeps []sdkMemberVariantDep) []*sdkMember {
+func (s *sdk) groupMemberVariantsByMemberThenType(ctx android.ModuleContext, targetBuildRelease *buildRelease, memberVariantDeps []sdkMemberVariantDep) []*sdkMember {
byType := make(map[android.SdkMemberType][]*sdkMember)
byName := make(map[string]*sdkMember)
@@ -268,13 +268,39 @@
}
var members []*sdkMember
for _, memberListProperty := range s.memberTypeListProperties() {
- membersOfType := byType[memberListProperty.memberType]
+ memberType := memberListProperty.memberType
+
+ if !isMemberTypeSupportedByTargetBuildRelease(memberType, targetBuildRelease) {
+ continue
+ }
+
+ membersOfType := byType[memberType]
members = append(members, membersOfType...)
}
return members
}
+// isMemberTypeSupportedByTargetBuildRelease returns true if the member type is supported by the
+// target build release.
+func isMemberTypeSupportedByTargetBuildRelease(memberType android.SdkMemberType, targetBuildRelease *buildRelease) bool {
+ supportedByTargetBuildRelease := true
+ supportedBuildReleases := memberType.SupportedBuildReleases()
+ if supportedBuildReleases == "" {
+ supportedBuildReleases = "S+"
+ }
+
+ set, err := parseBuildReleaseSet(supportedBuildReleases)
+ if err != nil {
+ panic(fmt.Errorf("member type %s has invalid supported build releases %q: %s",
+ memberType.SdkPropertyName(), supportedBuildReleases, err))
+ }
+ if !set.contains(targetBuildRelease) {
+ supportedByTargetBuildRelease = false
+ }
+ return supportedByTargetBuildRelease
+}
+
func appendUniqueVariants(variants []android.SdkAware, newVariant android.SdkAware) []android.SdkAware {
for _, v := range variants {
if v == newVariant {
@@ -401,12 +427,15 @@
// Group the variants for each member module together and then group the members of each member
// type together.
- members := s.groupMemberVariantsByMemberThenType(ctx, memberVariantDeps)
+ members := s.groupMemberVariantsByMemberThenType(ctx, targetBuildRelease, memberVariantDeps)
// Create the prebuilt modules for each of the member modules.
traits := s.gatherTraits()
for _, member := range members {
memberType := member.memberType
+ if !memberType.ArePrebuiltsRequired() {
+ continue
+ }
name := member.name
requiredTraits := traits[name]
@@ -1293,6 +1322,119 @@
}
}
+// TODO(187910671): BEGIN - Remove once modules do not have an APEX and default variant.
+// variantCoordinate contains the coordinates used to identify a variant of an SDK member.
+type variantCoordinate struct {
+ // osType identifies the OS target of a variant.
+ osType android.OsType
+ // archId identifies the architecture and whether it is for the native bridge.
+ archId archId
+ // image is the image variant name.
+ image string
+ // linkType is the link type name.
+ linkType string
+}
+
+func getVariantCoordinate(ctx *memberContext, variant android.Module) variantCoordinate {
+ linkType := ""
+ if len(ctx.MemberType().SupportedLinkages()) > 0 {
+ linkType = getLinkType(variant)
+ }
+ return variantCoordinate{
+ osType: variant.Target().Os,
+ archId: archIdFromTarget(variant.Target()),
+ image: variant.ImageVariation().Variation,
+ linkType: linkType,
+ }
+}
+
+// selectApexVariantsWhereAvailable filters the input list of variants by selecting the APEX
+// specific variant for a specific variantCoordinate when there is both an APEX and default variant.
+//
+// There is a long-standing issue where a module that is added to an APEX has both an APEX and
+// default/platform variant created even when the module does not require a platform variant. As a
+// result an indirect dependency onto a module via the APEX will use the APEX variant, whereas a
+// direct dependency onto the module will use the default/platform variant. That would result in a
+// failure while attempting to optimize the properties for a member as it would have two variants
+// when only one was expected.
+//
+// This function mitigates that problem by detecting when there are two variants that differ only
+// by apex variant, where one is the default/platform variant and one is the APEX variant. In that
+// case it picks the APEX variant. It picks the APEX variant because that is the behavior that would
+// be expected
+func selectApexVariantsWhereAvailable(ctx *memberContext, variants []android.SdkAware) []android.SdkAware {
+ moduleCtx := ctx.sdkMemberContext
+
+ // Group the variants by coordinates.
+ variantsByCoord := make(map[variantCoordinate][]android.SdkAware)
+ for _, variant := range variants {
+ coord := getVariantCoordinate(ctx, variant)
+ variantsByCoord[coord] = append(variantsByCoord[coord], variant)
+ }
+
+ toDiscard := make(map[android.SdkAware]struct{})
+ for coord, list := range variantsByCoord {
+ count := len(list)
+ if count == 1 {
+ continue
+ }
+
+ variantsByApex := make(map[string]android.SdkAware)
+ conflictDetected := false
+ for _, variant := range list {
+ apexInfo := moduleCtx.OtherModuleProvider(variant, android.ApexInfoProvider).(android.ApexInfo)
+ apexVariationName := apexInfo.ApexVariationName
+ // If there are two variants for a specific APEX variation then there is conflict.
+ if _, ok := variantsByApex[apexVariationName]; ok {
+ conflictDetected = true
+ break
+ }
+ variantsByApex[apexVariationName] = variant
+ }
+
+ // If there are more than 2 apex variations or one of the apex variations is not the
+ // default/platform variation then there is a conflict.
+ if len(variantsByApex) != 2 {
+ conflictDetected = true
+ } else if _, ok := variantsByApex[""]; !ok {
+ conflictDetected = true
+ }
+
+ // If there are no conflicts then add the default/platform variation to the list to remove.
+ if !conflictDetected {
+ toDiscard[variantsByApex[""]] = struct{}{}
+ continue
+ }
+
+ // There are duplicate variants at this coordinate and they are not the default and APEX variant
+ // so fail.
+ variantDescriptions := []string{}
+ for _, m := range list {
+ variantDescriptions = append(variantDescriptions, fmt.Sprintf(" %s", m.String()))
+ }
+
+ moduleCtx.ModuleErrorf("multiple conflicting variants detected for OsType{%s}, %s, Image{%s}, Link{%s}\n%s",
+ coord.osType, coord.archId.String(), coord.image, coord.linkType,
+ strings.Join(variantDescriptions, "\n"))
+ }
+
+ // If there are any variants to discard then remove them from the list of variants, while
+ // preserving the order.
+ if len(toDiscard) > 0 {
+ filtered := []android.SdkAware{}
+ for _, variant := range variants {
+ if _, ok := toDiscard[variant]; !ok {
+ filtered = append(filtered, variant)
+ }
+ }
+ variants = filtered
+ }
+
+ return variants
+}
+
+// TODO(187910671): END - Remove once modules do not have an APEX and default variant.
+
type baseInfo struct {
Properties android.SdkMemberProperties
}
@@ -1348,7 +1490,14 @@
if commonVariants, ok := variantsByArchId[commonArchId]; ok {
if len(osTypeVariants) != 1 {
- panic(fmt.Errorf("Expected to only have 1 variant when arch type is common but found %d", len(osTypeVariants)))
+ variants := []string{}
+ for _, m := range osTypeVariants {
+ variants = append(variants, fmt.Sprintf(" %s", m.String()))
+ }
+ panic(fmt.Errorf("expected to only have 1 variant of %q when arch type is common but found %d\n%s",
+ ctx.Name(),
+ len(osTypeVariants),
+ strings.Join(variants, "\n")))
}
// A common arch type only has one variant and its properties should be treated
@@ -1828,7 +1977,8 @@
memberType := member.memberType
// Do not add the prefer property if the member snapshot module is a source module type.
- config := ctx.sdkMemberContext.Config()
+ moduleCtx := ctx.sdkMemberContext
+ config := moduleCtx.Config()
if !memberType.UsesSourceModuleTypeInSnapshot() {
// Set the prefer based on the environment variable. This is a temporary work around to allow a
// snapshot to be created that sets prefer: true.
@@ -1853,9 +2003,10 @@
}
}
+ variants := selectApexVariantsWhereAvailable(ctx, member.variants)
+
// Group the variants by os type.
variantsByOsType := make(map[android.OsType][]android.Module)
- variants := member.Variants()
for _, variant := range variants {
osType := variant.Target().Os
variantsByOsType[osType] = append(variantsByOsType[osType], variant)
@@ -1901,7 +2052,7 @@
}
// Extract properties which are common across all architectures and os types.
- extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, commonProperties, osSpecificPropertiesContainers)
+ extractCommonProperties(moduleCtx, commonValueExtractor, commonProperties, osSpecificPropertiesContainers)
// Add the common properties to the module.
addSdkMemberPropertiesToSet(ctx, commonProperties, bpModule)
diff --git a/tests/lib.sh b/tests/lib.sh
index 0c78cdf..69ad201 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -116,6 +116,7 @@
function create_mock_bazel {
copy_directory build/bazel
+ copy_directory build/bazel_common_rules
symlink_directory prebuilts/bazel
symlink_directory prebuilts/clang
diff --git a/ui/build/config.go b/ui/build/config.go
index 59b01b3..cbf1986 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -156,10 +156,15 @@
// experiments system to control Soong features dynamically.
func fetchEnvConfig(ctx Context, config *configImpl, envConfigName string) error {
configName := envConfigName + "." + jsonSuffix
- expConfigFetcher := &smpb.ExpConfigFetcher{}
+ expConfigFetcher := &smpb.ExpConfigFetcher{Filename: &configName}
defer func() {
ctx.Metrics.ExpConfigFetcher(expConfigFetcher)
}()
+ if !config.GoogleProdCredsExist() {
+ status := smpb.ExpConfigFetcher_MISSING_GCERT
+ expConfigFetcher.Status = &status
+ return nil
+ }
s, err := os.Stat(configFetcher)
if err != nil {
@@ -1242,10 +1247,40 @@
return "", fmt.Errorf("cannot generate a proxy socket address shorter than the limit of %v", maxNameLen)
}
+// IsGooglerEnvironment returns true if the current build is running
+// on a Google developer machine and false otherwise.
+func (c *configImpl) IsGooglerEnvironment() bool {
+ cf := "ANDROID_BUILD_ENVIRONMENT_CONFIG"
+ if v, ok := c.environ.Get(cf); ok {
+ return v == "googler"
+ }
+ return false
+}
+
+// GoogleProdCredsExist determine whether credentials exist on the
+// Googler machine to use remote execution.
+func (c *configImpl) GoogleProdCredsExist() bool {
+ if _, err := exec.Command("/usr/bin/prodcertstatus", "--simple_output", "--nocheck_loas").Output(); err != nil {
+ return false
+ }
+ return true
+}
+
+// UseRemoteBuild indicates whether to use a remote build acceleration system
+// to speed up the build.
func (c *configImpl) UseRemoteBuild() bool {
return c.UseGoma() || c.UseRBE()
}
+// StubbyExists checks whether the stubby binary exists on the machine running
+// the build.
+func (c *configImpl) StubbyExists() bool {
+ if _, err := exec.LookPath("stubby"); err != nil {
+ return false
+ }
+ return true
+}
+
// RemoteParallel controls how many remote jobs (i.e., commands which contain
// gomacc) are run in parallel. Note the parallelism of all other jobs is
// still limited by Parallel()
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 3e558f7..82fc15f 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -19,6 +19,7 @@
"os"
"path/filepath"
"runtime"
+ "strings"
"android/soong/ui/metrics"
)
@@ -126,6 +127,34 @@
}
}
+func prodCredsAuthType(config Config) bool {
+ authVar, val := config.rbeAuth()
+ if strings.Contains(authVar, "use_google_prod_creds") && val != "" && val != "false" {
+ return true
+ }
+ return false
+}
+
+// Check whether proper auth exists for RBE builds run within a
+// Google dev environment.
+func CheckProdCreds(ctx Context, config Config) {
+ if !config.IsGooglerEnvironment() {
+ return
+ }
+ if !config.StubbyExists() && prodCredsAuthType(config) {
+ fmt.Fprintln(ctx.Writer, "")
+ fmt.Fprintln(ctx.Writer, fmt.Sprintf("\033[33mWARNING: %q binary not found in $PATH, follow go/build-fast#opting-out-of-loas-credentials instead for authenticating with RBE.\033[0m", "stubby"))
+ fmt.Fprintln(ctx.Writer, "")
+ return
+ }
+ if config.GoogleProdCredsExist() {
+ return
+ }
+ fmt.Fprintln(ctx.Writer, "")
+ fmt.Fprintln(ctx.Writer, "\033[33mWARNING: Missing LOAS credentials, please run `gcert`. This will result in failing builds in the future, see go/rbe-android-default-announcement.\033[0m")
+ fmt.Fprintln(ctx.Writer, "")
+}
+
// DumpRBEMetrics creates a metrics protobuf file containing RBE related metrics.
// The protobuf file is created if RBE is enabled and the proxy service has
// started. The proxy service is shutdown in order to dump the RBE metrics to the
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index 4bc713b..2dd8299 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -220,9 +220,10 @@
type ExpConfigFetcher_ConfigStatus int32
const (
- ExpConfigFetcher_NO_CONFIG ExpConfigFetcher_ConfigStatus = 0
- ExpConfigFetcher_CONFIG ExpConfigFetcher_ConfigStatus = 1
- ExpConfigFetcher_ERROR ExpConfigFetcher_ConfigStatus = 2
+ ExpConfigFetcher_NO_CONFIG ExpConfigFetcher_ConfigStatus = 0
+ ExpConfigFetcher_CONFIG ExpConfigFetcher_ConfigStatus = 1
+ ExpConfigFetcher_ERROR ExpConfigFetcher_ConfigStatus = 2
+ ExpConfigFetcher_MISSING_GCERT ExpConfigFetcher_ConfigStatus = 3
)
// Enum value maps for ExpConfigFetcher_ConfigStatus.
@@ -231,11 +232,13 @@
0: "NO_CONFIG",
1: "CONFIG",
2: "ERROR",
+ 3: "MISSING_GCERT",
}
ExpConfigFetcher_ConfigStatus_value = map[string]int32{
- "NO_CONFIG": 0,
- "CONFIG": 1,
- "ERROR": 2,
+ "NO_CONFIG": 0,
+ "CONFIG": 1,
+ "ERROR": 2,
+ "MISSING_GCERT": 3,
}
)
@@ -1578,7 +1581,7 @@
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, 0xc8, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66,
+ 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,
@@ -1587,22 +1590,23 @@
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, 0x34, 0x0a, 0x0c, 0x43, 0x6f, 0x6e,
+ 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, 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,
+ 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,
}
var (
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index 51dd523..4f8fe7f 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -251,6 +251,7 @@
NO_CONFIG = 0;
CONFIG = 1;
ERROR = 2;
+ MISSING_GCERT = 3;
}
// The result of the call to expconfigfetcher
// NO_CONFIG - Not part of experiment