Merge "Reland "Enable R8 full mode by default for apps"" into main
diff --git a/aconfig/Android.bp b/aconfig/Android.bp
index ae8276f..6927765 100644
--- a/aconfig/Android.bp
+++ b/aconfig/Android.bp
@@ -20,6 +20,7 @@
"aconfig_values.go",
"aconfig_value_set.go",
"all_aconfig_declarations.go",
+ "cc_aconfig_library.go",
"init.go",
"java_aconfig_library.go",
"testing.go",
@@ -28,6 +29,7 @@
"aconfig_declarations_test.go",
"aconfig_values_test.go",
"aconfig_value_set_test.go",
+ "java_aconfig_library_test.go",
],
pluginFor: ["soong_build"],
}
diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go
index 007d529..565d185 100644
--- a/aconfig/aconfig_declarations.go
+++ b/aconfig/aconfig_declarations.go
@@ -125,12 +125,12 @@
intermediatePath := android.PathForModuleOut(ctx, "intermediate.pb")
ctx.Build(pctx, android.BuildParams{
Rule: aconfigRule,
- Inputs: inputFiles,
Output: intermediatePath,
Description: "aconfig_declarations",
Args: map[string]string{
"release_version": ctx.Config().ReleaseVersion(),
"package": module.properties.Package,
+ "declarations": android.JoinPathsWithPrefix(inputFiles, "--declarations "),
"values": joinAndPrefix(" --values ", module.properties.Values),
},
})
diff --git a/aconfig/aconfig_declarations_test.go b/aconfig/aconfig_declarations_test.go
index e14ca38..e0d8f7d 100644
--- a/aconfig/aconfig_declarations_test.go
+++ b/aconfig/aconfig_declarations_test.go
@@ -26,7 +26,10 @@
aconfig_declarations {
name: "module_name",
package: "com.example.package",
- srcs: ["foo.aconfig"],
+ srcs: [
+ "foo.aconfig",
+ "bar.aconfig",
+ ],
}
`
result := runTest(t, android.FixtureExpectsNoErrors, bp)
diff --git a/aconfig/cc_aconfig_library.go b/aconfig/cc_aconfig_library.go
new file mode 100644
index 0000000..14090bc
--- /dev/null
+++ b/aconfig/cc_aconfig_library.go
@@ -0,0 +1,128 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package aconfig
+
+import (
+ "android/soong/android"
+ "android/soong/cc"
+ "github.com/google/blueprint"
+
+ "fmt"
+ "strings"
+)
+
+type ccDeclarationsTagType struct {
+ blueprint.BaseDependencyTag
+}
+
+var ccDeclarationsTag = ccDeclarationsTagType{}
+
+type CcAconfigLibraryProperties struct {
+ // name of the aconfig_declarations module to generate a library for
+ Aconfig_declarations string
+}
+
+type CcAconfigLibraryCallbacks struct {
+ properties *CcAconfigLibraryProperties
+
+ generatedDir android.WritablePath
+ headerDir android.WritablePath
+ generatedCpp android.WritablePath
+ generatedH android.WritablePath
+}
+
+func CcAconfigLibraryFactory() android.Module {
+ callbacks := &CcAconfigLibraryCallbacks{
+ properties: &CcAconfigLibraryProperties{},
+ }
+ return cc.GeneratedCcLibraryModuleFactory("cc_aconfig_library", callbacks)
+}
+
+func (this *CcAconfigLibraryCallbacks) GeneratorInit(ctx cc.BaseModuleContext) {
+}
+
+func (this *CcAconfigLibraryCallbacks) GeneratorProps() []interface{} {
+ return []interface{}{this.properties}
+}
+
+func (this *CcAconfigLibraryCallbacks) GeneratorDeps(ctx cc.DepsContext, deps cc.Deps) cc.Deps {
+ // Add a dependency for the declarations module
+ declarations := this.properties.Aconfig_declarations
+ if len(declarations) == 0 {
+ ctx.PropertyErrorf("aconfig_declarations", "aconfig_declarations property required")
+ } else {
+ ctx.AddDependency(ctx.Module(), ccDeclarationsTag, declarations)
+ }
+
+ // Add a dependency for the aconfig flags base library
+ deps.SharedLibs = append(deps.SharedLibs, "server_configurable_flags")
+ // TODO: It'd be really nice if we could reexport this library and not make everyone do it.
+
+ return deps
+}
+
+func (this *CcAconfigLibraryCallbacks) GeneratorSources(ctx cc.ModuleContext) cc.GeneratedSource {
+ result := cc.GeneratedSource{}
+
+ // Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
+ declarationsModules := ctx.GetDirectDepsWithTag(ccDeclarationsTag)
+ if len(declarationsModules) != 1 {
+ panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
+ }
+ declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData)
+
+ // Figure out the generated file paths. This has to match aconfig's codegen_cpp.rs.
+ this.generatedDir = android.PathForModuleGen(ctx)
+
+ this.headerDir = android.PathForModuleGen(ctx, "include")
+ result.IncludeDirs = []android.Path{this.headerDir}
+ result.ReexportedDirs = []android.Path{this.headerDir}
+
+ basename := strings.ReplaceAll(declarations.Package, ".", "_")
+
+ this.generatedCpp = android.PathForModuleGen(ctx, basename+".cc")
+ result.Sources = []android.Path{this.generatedCpp}
+
+ this.generatedH = android.PathForModuleGen(ctx, "include", basename+".h")
+ result.Headers = []android.Path{this.generatedH}
+
+ return result
+}
+
+func (this *CcAconfigLibraryCallbacks) GeneratorFlags(ctx cc.ModuleContext, flags cc.Flags, deps cc.PathDeps) cc.Flags {
+ return flags
+}
+
+func (this *CcAconfigLibraryCallbacks) GeneratorBuildActions(ctx cc.ModuleContext, flags cc.Flags, deps cc.PathDeps) {
+ // Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
+ declarationsModules := ctx.GetDirectDepsWithTag(ccDeclarationsTag)
+ if len(declarationsModules) != 1 {
+ panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
+ }
+ declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData)
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: cppRule,
+ Input: declarations.IntermediatePath,
+ Outputs: []android.WritablePath{
+ this.generatedCpp,
+ this.generatedH,
+ },
+ Description: "cc_aconfig_library",
+ Args: map[string]string{
+ "gendir": this.generatedDir.String(),
+ },
+ })
+}
diff --git a/aconfig/init.go b/aconfig/init.go
index 161fd42..37167aa 100644
--- a/aconfig/init.go
+++ b/aconfig/init.go
@@ -27,23 +27,24 @@
blueprint.RuleParams{
Command: `${aconfig} create-cache` +
` --package ${package}` +
- ` --declarations ${in}` +
+ ` ${declarations}` +
` ${values}` +
` --cache ${out}.tmp` +
- ` && ( if cmp -s ${out}.tmp ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`,
+ ` && ( if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`,
// ` --build-id ${release_version}` +
CommandDeps: []string{
"${aconfig}",
},
Restat: true,
- }, "release_version", "package", "values")
+ }, "release_version", "package", "declarations", "values")
// For java_aconfig_library: Generate java file
- srcJarRule = pctx.AndroidStaticRule("aconfig_srcjar",
+ javaRule = pctx.AndroidStaticRule("java_aconfig_library",
blueprint.RuleParams{
Command: `rm -rf ${out}.tmp` +
` && mkdir -p ${out}.tmp` +
` && ${aconfig} create-java-lib` +
+ ` --mode ${mode}` +
` --cache ${in}` +
` --out ${out}.tmp` +
` && $soong_zip -write_if_changed -jar -o ${out} -C ${out}.tmp -D ${out}.tmp` +
@@ -53,7 +54,21 @@
"$soong_zip",
},
Restat: true,
- })
+ }, "mode")
+
+ // For java_aconfig_library: Generate java file
+ cppRule = pctx.AndroidStaticRule("cc_aconfig_library",
+ blueprint.RuleParams{
+ Command: `rm -rf ${gendir}` +
+ ` && mkdir -p ${gendir}` +
+ ` && ${aconfig} create-cpp-lib` +
+ ` --cache ${in}` +
+ ` --out ${gendir}`,
+ CommandDeps: []string{
+ "$aconfig",
+ "$soong_zip",
+ },
+ }, "gendir")
// For all_aconfig_declarations
allDeclarationsRule = pctx.AndroidStaticRule("all_aconfig_declarations_dump",
@@ -75,6 +90,7 @@
ctx.RegisterModuleType("aconfig_declarations", DeclarationsFactory)
ctx.RegisterModuleType("aconfig_values", ValuesFactory)
ctx.RegisterModuleType("aconfig_value_set", ValueSetFactory)
+ ctx.RegisterModuleType("cc_aconfig_library", CcAconfigLibraryFactory)
ctx.RegisterModuleType("java_aconfig_library", JavaDeclarationsLibraryFactory)
ctx.RegisterParallelSingletonType("all_aconfig_declarations", AllAconfigDeclarationsFactory)
}
diff --git a/aconfig/java_aconfig_library.go b/aconfig/java_aconfig_library.go
index 0eeb14f..53f8bd1 100644
--- a/aconfig/java_aconfig_library.go
+++ b/aconfig/java_aconfig_library.go
@@ -30,6 +30,9 @@
type JavaAconfigDeclarationsLibraryProperties struct {
// name of the aconfig_declarations module to generate a library for
Aconfig_declarations string
+
+ // whether to generate test mode version of the library
+ Test bool
}
type JavaAconfigDeclarationsLibraryCallbacks struct {
@@ -51,7 +54,7 @@
}
}
-func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuildActions(ctx android.ModuleContext) android.Path {
+func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuildActions(module *java.GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path {
// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
declarationsModules := ctx.GetDirectDepsWithTag(declarationsTag)
if len(declarationsModules) != 1 {
@@ -59,13 +62,27 @@
}
declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData)
+ // Generate the action to build the srcjar
srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar")
+ var mode string
+ if callbacks.properties.Test {
+ mode = "test"
+ } else {
+ mode = "production"
+ }
ctx.Build(pctx, android.BuildParams{
- Rule: srcJarRule,
+ Rule: javaRule,
Input: declarations.IntermediatePath,
Output: srcJarPath,
Description: "aconfig.srcjar",
+ Args: map[string]string{
+ "mode": mode,
+ },
})
+ // Tell the java module about the .aconfig files, so they can be propagated up the dependency chain.
+ // TODO: It would be nice to have that propagation code here instead of on java.Module and java.JavaInfo.
+ module.AddAconfigIntermediate(declarations.IntermediatePath)
+
return srcJarPath
}
diff --git a/aconfig/java_aconfig_library_test.go b/aconfig/java_aconfig_library_test.go
new file mode 100644
index 0000000..af50848
--- /dev/null
+++ b/aconfig/java_aconfig_library_test.go
@@ -0,0 +1,191 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package aconfig
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+
+ "android/soong/android"
+ "android/soong/java"
+)
+
+// Note: These tests cover the code in the java package. It'd be ideal of that code could
+// be in the aconfig package.
+
+// With the bp parameter that defines a my_module, make sure it has the LOCAL_ACONFIG_FILES entries
+func runJavaAndroidMkTest(t *testing.T, bp string) {
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithAconfigBuildComponents,
+ java.PrepareForTestWithJavaDefaultModules).
+ ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
+ RunTestWithBp(t, bp+`
+ aconfig_declarations {
+ name: "my_aconfig_declarations",
+ package: "com.example.package",
+ srcs: ["foo.aconfig"],
+ }
+
+ java_aconfig_library {
+ name: "my_java_aconfig_library",
+ aconfig_declarations: "my_aconfig_declarations",
+ }
+ `)
+
+ module := result.ModuleForTests("my_module", "android_common").Module()
+
+ entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0]
+
+ makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"]
+ android.AssertIntEquals(t, "len(LOCAL_ACONFIG_FILES)", 1, len(makeVar))
+ if !strings.HasSuffix(makeVar[0], "intermediate.pb") {
+ t.Errorf("LOCAL_ACONFIG_FILES should end with /intermediates.pb, instead it is: %s", makeVar[0])
+ }
+}
+
+func TestAndroidMkJavaLibrary(t *testing.T) {
+ bp := `
+ java_library {
+ name: "my_module",
+ srcs: [
+ "src/foo.java",
+ ],
+ static_libs: [
+ "my_java_aconfig_library",
+ ],
+ platform_apis: true,
+ }
+ `
+
+ runJavaAndroidMkTest(t, bp)
+}
+
+func TestAndroidMkAndroidApp(t *testing.T) {
+ bp := `
+ android_app {
+ name: "my_module",
+ srcs: [
+ "src/foo.java",
+ ],
+ static_libs: [
+ "my_java_aconfig_library",
+ ],
+ platform_apis: true,
+ }
+ `
+
+ runJavaAndroidMkTest(t, bp)
+}
+
+func TestAndroidMkBinary(t *testing.T) {
+ bp := `
+ java_binary {
+ name: "my_module",
+ srcs: [
+ "src/foo.java",
+ ],
+ static_libs: [
+ "my_java_aconfig_library",
+ ],
+ platform_apis: true,
+ main_class: "foo",
+ }
+ `
+
+ runJavaAndroidMkTest(t, bp)
+}
+
+func TestAndroidMkAndroidLibrary(t *testing.T) {
+ bp := `
+ android_library {
+ name: "my_module",
+ srcs: [
+ "src/foo.java",
+ ],
+ static_libs: [
+ "my_java_aconfig_library",
+ ],
+ platform_apis: true,
+ }
+ `
+
+ runJavaAndroidMkTest(t, bp)
+}
+
+func TestAndroidMkBinaryThatLinksAgainstAar(t *testing.T) {
+ // Tests AndroidLibrary's propagation of flags through JavaInfo
+ bp := `
+ android_library {
+ name: "some_library",
+ srcs: [
+ "src/foo.java",
+ ],
+ static_libs: [
+ "my_java_aconfig_library",
+ ],
+ platform_apis: true,
+ }
+ java_binary {
+ name: "my_module",
+ srcs: [
+ "src/bar.java",
+ ],
+ static_libs: [
+ "some_library",
+ ],
+ platform_apis: true,
+ main_class: "foo",
+ }
+ `
+
+ runJavaAndroidMkTest(t, bp)
+}
+
+func testCodegenMode(t *testing.T, bpMode string, ruleMode string) {
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithAconfigBuildComponents,
+ java.PrepareForTestWithJavaDefaultModules).
+ ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
+ RunTestWithBp(t, fmt.Sprintf(`
+ aconfig_declarations {
+ name: "my_aconfig_declarations",
+ package: "com.example.package",
+ srcs: ["foo.aconfig"],
+ }
+
+ java_aconfig_library {
+ name: "my_java_aconfig_library",
+ aconfig_declarations: "my_aconfig_declarations",
+ %s
+ }
+ `, bpMode))
+
+ module := result.ModuleForTests("my_java_aconfig_library", "android_common")
+ rule := module.Rule("java_aconfig_library")
+ android.AssertStringEquals(t, "rule must contain test mode", rule.Args["mode"], ruleMode)
+}
+
+func TestDefaultProdMode(t *testing.T) {
+ testCodegenMode(t, "", "production")
+}
+
+func TestProdMode(t *testing.T) {
+ testCodegenMode(t, "test: false,", "production")
+}
+
+func TestTestMode(t *testing.T) {
+ testCodegenMode(t, "test: true,", "test")
+}
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index d320599..d37dc02 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -121,6 +121,7 @@
"development/sdk": Bp2BuildDefaultTrueRecursively,
"external/aac": Bp2BuildDefaultTrueRecursively,
+ "external/abseil-cpp": Bp2BuildDefaultTrueRecursively,
"external/arm-optimized-routines": Bp2BuildDefaultTrueRecursively,
"external/auto": Bp2BuildDefaultTrue,
"external/auto/android-annotation-stubs": Bp2BuildDefaultTrueRecursively,
@@ -141,11 +142,12 @@
"external/expat": Bp2BuildDefaultTrueRecursively,
"external/f2fs-tools": Bp2BuildDefaultTrue,
"external/flac": Bp2BuildDefaultTrueRecursively,
+ "external/flatbuffers": Bp2BuildDefaultTrueRecursively,
"external/fmtlib": Bp2BuildDefaultTrueRecursively,
"external/fsverity-utils": Bp2BuildDefaultTrueRecursively,
- "external/guava": Bp2BuildDefaultTrueRecursively,
"external/google-benchmark": Bp2BuildDefaultTrueRecursively,
"external/googletest": Bp2BuildDefaultTrueRecursively,
+ "external/guava": Bp2BuildDefaultTrueRecursively,
"external/gwp_asan": Bp2BuildDefaultTrueRecursively,
"external/hamcrest": Bp2BuildDefaultTrueRecursively,
"external/icu": Bp2BuildDefaultTrueRecursively,
@@ -188,7 +190,11 @@
"external/ow2-asm": Bp2BuildDefaultTrueRecursively,
"external/pcre": Bp2BuildDefaultTrueRecursively,
"external/protobuf": Bp2BuildDefaultTrueRecursively,
+ "external/python/pyyaml/lib/yaml": Bp2BuildDefaultTrueRecursively,
"external/python/six": Bp2BuildDefaultTrueRecursively,
+ "external/python/jinja/src": Bp2BuildDefaultTrueRecursively,
+ "external/python/markupsafe/src": Bp2BuildDefaultTrueRecursively,
+ "external/python/setuptools": Bp2BuildDefaultTrueRecursively,
"external/rappor": Bp2BuildDefaultTrueRecursively,
"external/scudo": Bp2BuildDefaultTrueRecursively,
"external/selinux/checkpolicy": Bp2BuildDefaultTrueRecursively,
@@ -227,6 +233,7 @@
"frameworks/hardware/interfaces/stats/aidl": Bp2BuildDefaultTrue,
"frameworks/libs/modules-utils/build": Bp2BuildDefaultTrueRecursively,
"frameworks/libs/net/common/native": Bp2BuildDefaultTrueRecursively,
+ "frameworks/native": Bp2BuildDefaultTrue,
"frameworks/native/libs/adbd_auth": Bp2BuildDefaultTrueRecursively,
"frameworks/native/libs/arect": Bp2BuildDefaultTrueRecursively,
"frameworks/native/libs/gui": Bp2BuildDefaultTrue,
@@ -429,6 +436,7 @@
// external/bazelbuild-rules_android/... is needed by mixed builds, otherwise mixed builds analysis fails
// e.g. ERROR: Analysis of target '@soong_injection//mixed_builds:buildroot' failed
"external/bazelbuild-rules_android":/* recursive = */ true,
+ "external/bazelbuild-rules_java":/* recursive = */ true,
"external/bazelbuild-rules_license":/* recursive = */ true,
"external/bazelbuild-rules_go":/* recursive = */ true,
"external/bazelbuild-kotlin-rules":/* recursive = */ true,
@@ -473,6 +481,8 @@
Bp2buildModuleAlwaysConvertList = []string{
"libidmap2_policies",
"libSurfaceFlingerProp",
+ "toolbox_input_labels",
+
// cc mainline modules
// com.android.media.swcodec
@@ -490,7 +500,6 @@
"code_coverage.policy.other",
"codec2_soft_exports",
"compatibility_matrix_schema",
- "flatbuffer_headers",
"framework-connectivity-protos",
"gemmlowp_headers",
"gl_headers",
@@ -613,10 +622,6 @@
"libhidlbase", // needed by cc_hidl_library
"libhidl_gtest_helper",
- //frameworks/native
- "framework_native_aidl_binder",
- "framework_native_aidl_gui",
-
//frameworks/native/libs/input
"inputconstants_aidl",
@@ -674,6 +679,7 @@
"libcodec2_hidl@1.2",
"libcodec2_hidl_plugin_stub",
"libcodec2_hidl_plugin",
+ "libcodec2_hal_common",
"libstagefright_bufferqueue_helper_novndk",
"libGLESv2",
"libEGL",
@@ -763,6 +769,7 @@
// Mainline Module Apps
"CaptivePortalLogin",
+ "ModuleMetadata",
"libstagefright_headers",
@@ -805,6 +812,14 @@
"rs-headers",
"rs_script_api",
"libRSDispatch",
+
+ // hal_unit_tests and deps
+ "android.hardware.contexthub_interface", // created implicitly by android.hardware.contexthub
+ "chre_flatbuffers",
+ "event_logger",
+ "hal_unit_tests",
+
+ "merge_annotation_zips_test",
}
Bp2buildModuleTypeAlwaysConvertList = []string{
@@ -828,6 +843,10 @@
// the "prebuilt_" prefix to the name, so that it's differentiable from
// the source versions within Soong's module graph.
Bp2buildModuleDoNotConvertList = []string{
+ // TODO(b/263326760): Failed already.
+ "minijail_compiler_unittest",
+ "minijail_parser_unittest",
+
// Depends on unconverted libandroid, libgui
"dvr_buffer_queue-test",
"dvr_display-test",
@@ -909,7 +928,10 @@
"libart_headers", // depends on unconverted modules: art_libartbase_headers
"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
+ "libart-runtime", // depends on unconverted modules: apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api, art_operator_srcs, libcpu_features, libodrstatslog, libelffile, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfile, libnativebridge, libnativeloader, libsigchain, libartbase, libprofile, cpp-define-generator-asm-support
+ "libart-runtime-for-test", // depends on unconverted modules: apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api, art_operator_srcs, libcpu_features, libodrstatslog, libelffile, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfile, libnativebridge, libnativeloader, libsigchain, libartbase, libprofile, cpp-define-generator-asm-support
"libartd", // depends on unconverted modules: art_operator_srcs, libcpu_features, libodrstatslog, libelffiled, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfiled, libnativebridge, libnativeloader, libsigchain, libartbased, libprofiled, cpp-define-generator-asm-support, apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api
+ "libartd-runtime", // depends on unconverted modules: art_operator_srcs, libcpu_features, libodrstatslog, libelffiled, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfiled, libnativebridge, libnativeloader, libsigchain, libartbased, libprofiled, cpp-define-generator-asm-support, apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api
"libartd-runtime-gtest", // depends on unconverted modules: libgtest_isolated, libartd-compiler, libdexfiled, libprofiled, libartbased, libartbased-art-gtest
"libdebuggerd", // depends on unconverted module: libdexfile
"libdebuggerd_handler", // depends on unconverted module libdebuggerd_handler_core
@@ -931,9 +953,6 @@
"test_fips", // depends on unconverted modules: adb
"timezone-host", // depends on unconverted modules: art.module.api.annotations
- // '//bionic/libc:libc_bp2build_cc_library_static' is duplicated in the 'deps' attribute of rule
- "toybox-static",
-
// aidl files not created
"overlayable_policy_aidl_interface",
@@ -1016,6 +1035,7 @@
"bionic-unit-tests-static",
"boringssl_crypto_test",
"boringssl_ssl_test",
+ "boringssl_test_support", //b/244431896
"cfi_test_helper",
"cfi_test_helper2",
"cintltst32",
@@ -1493,8 +1513,6 @@
"ICU4CTestRunner",
"DeviceLongPollingStubTest",
- "HelloWorldHostTest", // TODO(b/280452825): Convert HelloWorldHostTest to b test
-
"libprotobuf-full-test", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory
"libprotobuf-lite-test", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory
@@ -1509,73 +1527,6 @@
"libartd-runtime-gtest",
}
- 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
- "minijail_constants_json", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module.
-
- "cap_names.h", // TODO(b/204913827) runfiles need to be handled in mixed builds
- "libcap", // TODO(b/204913827) runfiles need to be handled in mixed builds
- "libprotobuf-cpp-full", "libprotobuf-cpp-lite", // Unsupported product&vendor suffix. b/204811222 and b/204810610.
-
- // Depends on libprotobuf-cpp-*
- "libadb_pairing_connection",
- "libadb_pairing_connection_static",
- "libadb_pairing_server", "libadb_pairing_server_static",
-
- // java_import[_host] issues
- // tradefed prebuilts depend on libprotobuf
- "prebuilt_tradefed",
- "prebuilt_tradefed-test-framework",
- // handcrafted BUILD.bazel files in //prebuilts/...
- "prebuilt_r8lib-prebuilt",
- "prebuilt_sdk-core-lambda-stubs",
- "prebuilt_android-support-collections-nodeps",
- "prebuilt_android-arch-core-common-nodeps",
- "prebuilt_android-arch-lifecycle-common-java8-nodeps",
- "prebuilt_android-arch-lifecycle-common-nodeps",
- "prebuilt_android-support-annotations-nodeps",
- "prebuilt_android-arch-paging-common-nodeps",
- "prebuilt_android-arch-room-common-nodeps",
- // TODO(b/217750501) exclude_dirs property not supported
- "prebuilt_kotlin-reflect",
- "prebuilt_kotlin-stdlib",
- "prebuilt_kotlin-stdlib-jdk7",
- "prebuilt_kotlin-stdlib-jdk8",
- "prebuilt_kotlin-test",
- // TODO(b/217750501) exclude_files property not supported
- "prebuilt_currysrc_org.eclipse",
-
- // TODO(b/266459895): re-enable libunwindstack
- "libunwindstack",
- "libunwindstack_stdout_log",
- "libunwindstack_no_dex",
- "libunwindstack_utils",
- "unwind_reg_info",
- "libunwindstack_local",
- "unwind_for_offline",
- "unwind",
- "unwind_info",
- "unwind_symbols",
- "libEGL",
- "libGLESv2",
- "libc_malloc_debug",
- "libcodec2_hidl@1.0",
- "libcodec2_hidl@1.1",
- "libcodec2_hidl@1.2",
- "libfdtrack",
- "libgui",
- "libgui_bufferqueue_static",
- "libmedia_codecserviceregistrant",
- "libstagefright_bufferqueue_helper_novndk",
- "libutils_test",
- "libutilscallstack",
- "mediaswcodec",
- }
-
// Bazel prod-mode allowlist. Modules in this list are built by Bazel
// in either prod mode or staging mode.
ProdMixedBuildsEnabledList = []string{
@@ -1598,14 +1549,6 @@
"test_com.android.neuralnetworks",
"libneuralnetworks",
"libneuralnetworks_static",
- }
-
- // Staging-mode allowlist. Modules in this list are only built
- // by Bazel with --bazel-mode-staging. This list should contain modules
- // which will soon be added to the prod allowlist.
- // It is implicit that all modules in ProdMixedBuildsEnabledList will
- // also be built - do not add them to this list.
- StagingMixedBuildsEnabledList = []string{
// M13: media.swcodec launch
"com.android.media.swcodec",
"test_com.android.media.swcodec",
@@ -1613,20 +1556,26 @@
"libcodec2_hidl@1.0",
}
+ // Staging-mode allowlist. Modules in this list are only built
+ // by Bazel with --bazel-mode-staging. This list should contain modules
+ // which will soon be added to the prod allowlist.
+ // It is implicit that all modules in ProdMixedBuildsEnabledList will
+ // also be built - do not add them to this list.
+ StagingMixedBuildsEnabledList = []string{}
+
// These should be the libs that are included by the apexes in the ProdMixedBuildsEnabledList
ProdDclaMixedBuildsEnabledList = []string{
"libbase",
"libc++",
"libcrypto",
"libcutils",
- }
-
- // These should be the libs that are included by the apexes in the StagingMixedBuildsEnabledList
- StagingDclaMixedBuildsEnabledList = []string{
"libstagefright_flacdec",
"libutils",
}
+ // These should be the libs that are included by the apexes in the StagingMixedBuildsEnabledList
+ StagingDclaMixedBuildsEnabledList = []string{}
+
// TODO(b/269342245): Enable the rest of the DCLA libs
// "libssl",
@@ -1638,4 +1587,14 @@
"art_": DEFAULT_PRIORITIZED_WEIGHT,
"ndk_library": DEFAULT_PRIORITIZED_WEIGHT,
}
+
+ BazelSandwichTargets = []struct {
+ Label string
+ Host bool
+ }{
+ {
+ Label: "//build/bazel/examples/partitions:system_image",
+ Host: false,
+ },
+ }
)
diff --git a/android/api_levels.go b/android/api_levels.go
index 2391e6c..44c8640 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -275,10 +275,6 @@
// relocations itself.
var FirstPackedRelocationsVersion = uncheckedFinalApiLevel(23)
-// The first API level that does not require NDK code to link
-// libandroid_support.
-var FirstNonLibAndroidSupportVersion = uncheckedFinalApiLevel(21)
-
// LastWithoutModuleLibCoreSystemModules is the last API level where prebuilts/sdk does not contain
// a core-for-system-modules.jar for the module-lib API scope.
var LastWithoutModuleLibCoreSystemModules = uncheckedFinalApiLevel(31)
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 5d93f06..fd4b5ef 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -16,6 +16,8 @@
import (
"bytes"
+ "crypto/sha1"
+ "encoding/hex"
"fmt"
"os"
"path"
@@ -184,6 +186,8 @@
// Returns the depsets defined in Bazel's aquery response.
AqueryDepsets() []bazel.AqueryDepset
+
+ QueueBazelSandwichCqueryRequests(config Config) error
}
type bazelRunner interface {
@@ -262,6 +266,10 @@
m.BazelRequests[key] = true
}
+func (m MockBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
+ panic("unimplemented")
+}
+
func (m MockBazelContext) GetOutputFiles(label string, _ configKey) ([]string, error) {
result, ok := m.LabelToOutputFiles[label]
if !ok {
@@ -422,6 +430,10 @@
panic("unimplemented")
}
+func (n noopBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
+ panic("unimplemented")
+}
+
func (n noopBazelContext) GetOutputFiles(_ string, _ configKey) ([]string, error) {
panic("unimplemented")
}
@@ -1040,6 +1052,50 @@
allBazelCommands = []bazelCommand{aqueryCmd, cqueryCmd, buildCmd}
)
+func GetBazelSandwichCqueryRequests(config Config) ([]cqueryKey, error) {
+ result := make([]cqueryKey, 0, len(allowlists.BazelSandwichTargets))
+ // Note that bazel "targets" are different from soong "targets", the bazel targets are
+ // synonymous with soong modules, and soong targets are a configuration a module is built in.
+ for _, target := range allowlists.BazelSandwichTargets {
+ var soongTarget Target
+ if target.Host {
+ soongTarget = config.BuildOSTarget
+ } else {
+ soongTarget = config.AndroidCommonTarget
+ if soongTarget.Os.Class != Device {
+ // kernel-build-tools seems to set the AndroidCommonTarget to a linux host
+ // target for some reason, disable device builds in that case.
+ continue
+ }
+ }
+
+ result = append(result, cqueryKey{
+ label: target.Label,
+ requestType: cquery.GetOutputFiles,
+ configKey: configKey{
+ arch: soongTarget.Arch.String(),
+ osType: soongTarget.Os,
+ },
+ })
+ }
+ return result, nil
+}
+
+// QueueBazelSandwichCqueryRequests queues cquery requests for all the bazel labels in
+// bazel_sandwich_targets. These will later be given phony targets so that they can be built on the
+// command line.
+func (context *mixedBuildBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
+ requests, err := GetBazelSandwichCqueryRequests(config)
+ if err != nil {
+ return err
+ }
+ for _, request := range requests {
+ context.QueueBazelRequest(request.label, request.requestType, request.configKey)
+ }
+
+ return nil
+}
+
// Issues commands to Bazel to receive results for all cquery requests
// queued in the BazelContext.
func (context *mixedBuildBazelContext) InvokeBazel(config Config, ctx invokeBazelContext) error {
@@ -1222,7 +1278,11 @@
ctx.AddNinjaFileDeps(file)
}
+ depsetHashToDepset := map[string]bazel.AqueryDepset{}
+
for _, depset := range ctx.Config().BazelContext.AqueryDepsets() {
+ depsetHashToDepset[depset.ContentHash] = depset
+
var outputs []Path
var orderOnlies []Path
for _, depsetDepHash := range depset.TransitiveDepSetHashes {
@@ -1249,6 +1309,11 @@
executionRoot := path.Join(ctx.Config().BazelContext.OutputBase(), "execroot", "__main__")
bazelOutDir := path.Join(executionRoot, "bazel-out")
+ rel, err := filepath.Rel(ctx.Config().OutDir(), executionRoot)
+ if err != nil {
+ ctx.Errorf("%s", err.Error())
+ }
+ dotdotsToOutRoot := strings.Repeat("../", strings.Count(rel, "/")+1)
for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
// nil build statements are a valid case where we do not create an action because it is
// unnecessary or handled by other processing
@@ -1257,7 +1322,31 @@
}
if len(buildStatement.Command) > 0 {
rule := NewRuleBuilder(pctx, ctx)
- createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx)
+ intermediateDir, intermediateDirHash := intermediatePathForSboxMixedBuildAction(ctx, buildStatement)
+ if buildStatement.ShouldRunInSbox {
+ // Create a rule to build the output inside a sandbox
+ // This will create two changes of working directory
+ // 1. From ANDROID_BUILD_TOP to sbox top
+ // 2. From sbox top to a a synthetic mixed build execution root relative to it
+ // Finally, the outputs will be copied to intermediateDir
+ rule.Sbox(intermediateDir,
+ PathForOutput(ctx, "mixed_build_sbox_intermediates", intermediateDirHash+".textproto")).
+ SandboxInputs().
+ // Since we will cd to mixed build execution root, set sbox's out subdir to empty
+ // Without this, we will try to copy from $SBOX_SANDBOX_DIR/out/out/bazel/output/execroot/__main__/...
+ SetSboxOutDirDirAsEmpty()
+
+ // Create another set of rules to copy files from the intermediate dir to mixed build execution root
+ for _, outputPath := range buildStatement.OutputPaths {
+ ctx.Build(pctx, BuildParams{
+ Rule: CpIfChanged,
+ Input: intermediateDir.Join(ctx, executionRoot, outputPath),
+ Output: PathForBazelOut(ctx, outputPath),
+ })
+ }
+ }
+ createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx, depsetHashToDepset, dotdotsToOutRoot)
+
desc := fmt.Sprintf("%s: %s", buildStatement.Mnemonic, buildStatement.OutputPaths)
rule.Build(fmt.Sprintf("bazel %d", index), desc)
continue
@@ -1302,12 +1391,45 @@
panic(fmt.Sprintf("unhandled build statement: %v", buildStatement))
}
}
+
+ // Create phony targets for all the bazel sandwich output files
+ requests, err := GetBazelSandwichCqueryRequests(ctx.Config())
+ if err != nil {
+ ctx.Errorf(err.Error())
+ }
+ for _, request := range requests {
+ files, err := ctx.Config().BazelContext.GetOutputFiles(request.label, request.configKey)
+ if err != nil {
+ ctx.Errorf(err.Error())
+ }
+ filesAsPaths := make([]Path, 0, len(files))
+ for _, file := range files {
+ filesAsPaths = append(filesAsPaths, PathForBazelOut(ctx, file))
+ }
+ ctx.Phony("bazel_sandwich", filesAsPaths...)
+ }
+ ctx.Phony("checkbuild", PathForPhony(ctx, "bazel_sandwich"))
+}
+
+// Returns a out dir path for a sandboxed mixed build action
+func intermediatePathForSboxMixedBuildAction(ctx PathContext, statement *bazel.BuildStatement) (OutputPath, string) {
+ // An artifact can be generated by a single buildstatement.
+ // Use the hash of the first artifact to create a unique path
+ uniqueDir := sha1.New()
+ uniqueDir.Write([]byte(statement.OutputPaths[0]))
+ uniqueDirHashString := hex.EncodeToString(uniqueDir.Sum(nil))
+ return PathForOutput(ctx, "mixed_build_sbox_intermediates", uniqueDirHashString), uniqueDirHashString
}
// Register bazel-owned build statements (obtained from the aquery invocation).
-func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx BuilderContext) {
+func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx BuilderContext, depsetHashToDepset map[string]bazel.AqueryDepset, dotdotsToOutRoot string) {
// executionRoot is the action cwd.
- cmd.Text(fmt.Sprintf("cd '%s' &&", executionRoot))
+ if buildStatement.ShouldRunInSbox {
+ // mkdir -p ensures that the directory exists when run via sbox
+ cmd.Text(fmt.Sprintf("mkdir -p '%s' && cd '%s' &&", executionRoot, executionRoot))
+ } else {
+ cmd.Text(fmt.Sprintf("cd '%s' &&", executionRoot))
+ }
// Remove old outputs, as some actions might not rerun if the outputs are detected.
if len(buildStatement.OutputPaths) > 0 {
@@ -1323,25 +1445,47 @@
cmd.Flag(pair.Key + "=" + pair.Value)
}
+ command := buildStatement.Command
+ command = strings.ReplaceAll(command, "{DOTDOTS_TO_OUTPUT_ROOT}", dotdotsToOutRoot)
+
// The actual Bazel action.
- if len(buildStatement.Command) > 16*1024 {
+ if len(command) > 16*1024 {
commandFile := PathForBazelOut(ctx, buildStatement.OutputPaths[0]+".sh")
- WriteFileRule(ctx, commandFile, buildStatement.Command)
+ WriteFileRule(ctx, commandFile, command)
cmd.Text("bash").Text(buildStatement.OutputPaths[0] + ".sh").Implicit(commandFile)
} else {
- cmd.Text(buildStatement.Command)
+ cmd.Text(command)
}
for _, outputPath := range buildStatement.OutputPaths {
- cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath))
+ if buildStatement.ShouldRunInSbox {
+ // The full path has three components that get joined together
+ // 1. intermediate output dir that `sbox` will place the artifacts at
+ // 2. mixed build execution root
+ // 3. artifact path returned by aquery
+ intermediateDir, _ := intermediatePathForSboxMixedBuildAction(ctx, buildStatement)
+ cmd.ImplicitOutput(intermediateDir.Join(ctx, executionRoot, outputPath))
+ } else {
+ cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath))
+ }
}
for _, inputPath := range buildStatement.InputPaths {
cmd.Implicit(PathForBazelOut(ctx, inputPath))
}
for _, inputDepsetHash := range buildStatement.InputDepsetHashes {
- otherDepsetName := bazelDepsetName(inputDepsetHash)
- cmd.Implicit(PathForPhony(ctx, otherDepsetName))
+ if buildStatement.ShouldRunInSbox {
+ // Bazel depsets are phony targets that are used to group files.
+ // We need to copy the grouped files into the sandbox
+ ds, _ := depsetHashToDepset[inputDepsetHash]
+ cmd.Implicits(PathsForBazelOut(ctx, ds.DirectArtifacts))
+ } else {
+ otherDepsetName := bazelDepsetName(inputDepsetHash)
+ cmd.Implicit(PathForPhony(ctx, otherDepsetName))
+ }
+ }
+ for _, implicitPath := range buildStatement.ImplicitDeps {
+ cmd.Implicit(PathForArbitraryOutput(ctx, implicitPath))
}
if depfile := buildStatement.Depfile; depfile != nil {
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index 65cd5a8..9a3c8fc 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -181,13 +181,62 @@
cmd := RuleBuilderCommand{}
ctx := builderContextForTests{PathContextForTesting(TestConfig("out", nil, "", nil))}
- createCommand(&cmd, got[0], "test/exec_root", "test/bazel_out", ctx)
+ createCommand(&cmd, got[0], "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{}, "")
if actual, expected := cmd.buf.String(), testCase.command; expected != actual {
t.Errorf("expected: [%s], actual: [%s]", expected, actual)
}
}
}
+func TestMixedBuildSandboxedAction(t *testing.T) {
+ input := `{
+ "artifacts": [
+ { "id": 1, "path_fragment_id": 1 },
+ { "id": 2, "path_fragment_id": 2 }],
+ "actions": [{
+ "target_Id": 1,
+ "action_Key": "x",
+ "mnemonic": "x",
+ "arguments": ["touch", "foo"],
+ "input_dep_set_ids": [1],
+ "output_Ids": [1],
+ "primary_output_id": 1
+ }],
+ "dep_set_of_files": [
+ { "id": 1, "direct_artifact_ids": [1, 2] }],
+ "path_fragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "two" }]
+}`
+ data, err := JsonToActionGraphContainer(input)
+ if err != nil {
+ t.Error(err)
+ }
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{aqueryCmd: string(data)})
+
+ err = bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
+ if err != nil {
+ t.Fatalf("TestMixedBuildSandboxedAction did not expect error invoking Bazel, but got %s", err)
+ }
+
+ statement := bazelContext.BuildStatementsToRegister()[0]
+ statement.ShouldRunInSbox = true
+
+ cmd := RuleBuilderCommand{}
+ ctx := builderContextForTests{PathContextForTesting(TestConfig("out", nil, "", nil))}
+ createCommand(&cmd, statement, "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{}, "")
+ // Assert that the output is generated in an intermediate directory
+ // fe05bcdcdc4928012781a5f1a2a77cbb5398e106 is the sha1 checksum of "one"
+ if actual, expected := cmd.outputs[0].String(), "out/soong/mixed_build_sbox_intermediates/fe05bcdcdc4928012781a5f1a2a77cbb5398e106/test/exec_root/one"; expected != actual {
+ t.Errorf("expected: [%s], actual: [%s]", expected, actual)
+ }
+
+ // Assert the actual command remains unchanged inside the sandbox
+ if actual, expected := cmd.buf.String(), "mkdir -p 'test/exec_root' && cd 'test/exec_root' && rm -rf 'one' && touch foo"; expected != actual {
+ t.Errorf("expected: [%s], actual: [%s]", expected, actual)
+ }
+}
+
func TestCoverageFlagsAfterInvokeBazel(t *testing.T) {
testConfig.productVariables.ClangCoverage = boolPtr(true)
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index 2f5ff64..7568543 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -124,6 +124,7 @@
labels.Includes = []bazel.Label{}
return labels
}
+ modules = FirstUniqueStrings(modules)
for _, module := range modules {
bpText := module
if m := SrcIsModule(module); m == "" {
@@ -179,7 +180,7 @@
// paths, relative to the local module, or Bazel-labels (absolute if in a different package or
// relative if within the same package).
// Properties must have been annotated with struct tag `android:"path"` so that dependencies modules
-// will have already been handled by the path_deps mutator.
+// will have already been handled by the pathdeps mutator.
func BazelLabelForModuleSrc(ctx BazelConversionPathContext, paths []string) bazel.LabelList {
return BazelLabelForModuleSrcExcludes(ctx, paths, []string(nil))
}
@@ -189,7 +190,7 @@
// references in paths, minus those in excludes, relative to the local module, or Bazel-labels
// (absolute if in a different package or relative if within the same package).
// Properties must have been annotated with struct tag `android:"path"` so that dependencies modules
-// will have already been handled by the path_deps mutator.
+// will have already been handled by the pathdeps mutator.
func BazelLabelForModuleSrcExcludes(ctx BazelConversionPathContext, paths, excludes []string) bazel.LabelList {
excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil))
excluded := make([]string, 0, len(excludeLabels.Includes))
@@ -355,7 +356,7 @@
//
// Properties passed as the paths or excludes argument must have been annotated with struct tag
// `android:"path"` so that dependencies on other modules will have already been handled by the
-// path_deps mutator.
+// pathdeps mutator.
func expandSrcsForBazel(ctx BazelConversionPathContext, paths, expandedExcludes []string) bazel.LabelList {
if paths == nil {
return bazel.LabelList{}
diff --git a/android/config.go b/android/config.go
index fa43962..72ff224 100644
--- a/android/config.go
+++ b/android/config.go
@@ -18,7 +18,6 @@
// product variables necessary for soong_build's operation.
import (
- "bytes"
"encoding/json"
"fmt"
"os"
@@ -171,6 +170,19 @@
return c.config.TestProductVariables != nil
}
+// DisableHiddenApiChecks returns true if hiddenapi checks have been disabled.
+// For 'eng' target variant hiddenapi checks are disabled by default for performance optimisation,
+// but can be enabled by setting environment variable ENABLE_HIDDENAPI_FLAGS=true.
+// For other target variants hiddenapi check are enabled by default but can be disabled by
+// setting environment variable UNSAFE_DISABLE_HIDDENAPI_FLAGS=true.
+// If both ENABLE_HIDDENAPI_FLAGS=true and UNSAFE_DISABLE_HIDDENAPI_FLAGS=true, then
+// ENABLE_HIDDENAPI_FLAGS=true will be triggered and hiddenapi checks will be considered enabled.
+func (c Config) DisableHiddenApiChecks() bool {
+ return !c.IsEnvTrue("ENABLE_HIDDENAPI_FLAGS") &&
+ (c.IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") ||
+ Bool(c.productVariables.Eng))
+}
+
// MaxPageSizeSupported returns the max page size supported by the device. This
// value will define the ELF segment alignment for binaries (executables and
// shared libraries).
@@ -202,10 +214,10 @@
// product configuration values are read from Kati-generated soong.variables.
type config struct {
// Options configurable with soong.variables
- productVariables productVariables
+ productVariables ProductVariables
// Only available on configs created by TestConfig
- TestProductVariables *productVariables
+ TestProductVariables *ProductVariables
// A specialized context object for Bazel/Soong mixed builds and migration
// purposes.
@@ -321,7 +333,7 @@
// loadFromConfigFile loads and decodes configuration options from a JSON file
// in the current working directory.
-func loadFromConfigFile(configurable *productVariables, filename string) error {
+func loadFromConfigFile(configurable *ProductVariables, filename string) error {
// Try to open the file
configFileReader, err := os.Open(filename)
defer configFileReader.Close()
@@ -373,7 +385,7 @@
// atomically writes the config file in case two copies of soong_build are running simultaneously
// (for example, docs generation and ninja manifest generation)
-func saveToConfigFile(config *productVariables, filename string) error {
+func saveToConfigFile(config *ProductVariables, filename string) error {
data, err := json.MarshalIndent(&config, "", " ")
if err != nil {
return fmt.Errorf("cannot marshal config data: %s", err.Error())
@@ -402,7 +414,7 @@
return nil
}
-func saveToBazelConfigFile(config *productVariables, outDir string) error {
+func saveToBazelConfigFile(config *ProductVariables, outDir string) error {
dir := filepath.Join(outDir, bazel.SoongInjectionDirName, "product_config")
err := createDirIfNonexistent(dir, os.ModePerm)
if err != nil {
@@ -431,32 +443,6 @@
return fmt.Errorf("cannot marshal arch variant product variable data: %s", err.Error())
}
- configJson, err := json.MarshalIndent(&config, "", " ")
- if err != nil {
- return fmt.Errorf("cannot marshal config data: %s", err.Error())
- }
- // The backslashes need to be escaped because this text is going to be put
- // inside a Starlark string literal.
- configJson = bytes.ReplaceAll(configJson, []byte("\\"), []byte("\\\\"))
-
- bzl := []string{
- bazel.GeneratedBazelFileWarning,
- fmt.Sprintf(`_product_vars = json.decode("""%s""")`, configJson),
- fmt.Sprintf(`_product_var_constraints = %s`, nonArchVariantProductVariablesJson),
- fmt.Sprintf(`_arch_variant_product_var_constraints = %s`, archVariantProductVariablesJson),
- "\n", `
-product_vars = _product_vars
-
-# TODO(b/269577299) Remove these when everything switches over to loading them from product_variable_constants.bzl
-product_var_constraints = _product_var_constraints
-arch_variant_product_var_constraints = _arch_variant_product_var_constraints
-`,
- }
- err = pathtools.WriteFileIfChanged(filepath.Join(dir, "product_variables.bzl"),
- []byte(strings.Join(bzl, "\n")), 0644)
- if err != nil {
- return fmt.Errorf("Could not write .bzl config file %s", err)
- }
err = pathtools.WriteFileIfChanged(filepath.Join(dir, "product_variable_constants.bzl"), []byte(fmt.Sprintf(`
product_var_constraints = %s
arch_variant_product_var_constraints = %s
@@ -1355,6 +1341,10 @@
return c.bazelForceEnabledModules
}
+func (c *config) IsVndkDeprecated() bool {
+ return !Bool(c.productVariables.KeepVndk)
+}
+
func (c *deviceConfig) Arches() []Arch {
var arches []Arch
for _, target := range c.config.Targets[Android] {
@@ -1932,6 +1922,10 @@
return c.config.productVariables.RequiresInsecureExecmemForSwiftshader
}
+func (c *deviceConfig) Release_aidl_use_unfrozen() bool {
+ return Bool(c.config.productVariables.Release_aidl_use_unfrozen)
+}
+
func (c *config) SelinuxIgnoreNeverallows() bool {
return c.productVariables.SelinuxIgnoreNeverallows
}
diff --git a/android/config_test.go b/android/config_test.go
index 9df5288..7d327a2 100644
--- a/android/config_test.go
+++ b/android/config_test.go
@@ -75,7 +75,7 @@
// run validateConfigAnnotations against each type that might have json annotations
func TestProductConfigAnnotations(t *testing.T) {
- err := validateConfigAnnotations(&productVariables{})
+ err := validateConfigAnnotations(&ProductVariables{})
if err != nil {
t.Errorf(err.Error())
}
@@ -88,7 +88,7 @@
}
}
-func verifyProductVariableMarshaling(t *testing.T, v productVariables) {
+func verifyProductVariableMarshaling(t *testing.T, v ProductVariables) {
dir := t.TempDir()
path := filepath.Join(dir, "test.variables")
err := saveToConfigFile(&v, path)
@@ -96,20 +96,20 @@
t.Errorf("Couldn't save default product config: %q", err)
}
- var v2 productVariables
+ var v2 ProductVariables
err = loadFromConfigFile(&v2, path)
if err != nil {
t.Errorf("Couldn't load default product config: %q", err)
}
}
func TestDefaultProductVariableMarshaling(t *testing.T) {
- v := productVariables{}
+ v := ProductVariables{}
v.SetDefaultConfig()
verifyProductVariableMarshaling(t, v)
}
func TestBootJarsMarshaling(t *testing.T) {
- v := productVariables{}
+ v := ProductVariables{}
v.SetDefaultConfig()
v.BootJars = ConfiguredJarList{
apexes: []string{"apex"},
diff --git a/android/configured_jars_test.go b/android/configured_jars_test.go
index 32c3613..4b586e4 100644
--- a/android/configured_jars_test.go
+++ b/android/configured_jars_test.go
@@ -21,7 +21,7 @@
func TestOverrideConfiguredJarLocationFor(t *testing.T) {
cfg := NullConfig("", "")
- cfg.productVariables = productVariables{
+ cfg.productVariables = ProductVariables{
ConfiguredJarLocationOverrides: []string{
"platform:libfoo-old:com.android.foo:libfoo-new",
"com.android.bar:libbar-old:platform:libbar-new",
diff --git a/android/fixture.go b/android/fixture.go
index dbc3bc5..6660afd 100644
--- a/android/fixture.go
+++ b/android/fixture.go
@@ -369,7 +369,7 @@
// Allow access to the product variables when preparing the fixture.
type FixtureProductVariables struct {
- *productVariables
+ *ProductVariables
}
// Modify product variables.
diff --git a/android/module.go b/android/module.go
index 384776a..4c781f6 100644
--- a/android/module.go
+++ b/android/module.go
@@ -4029,43 +4029,26 @@
JavaBp2buildTargetName() string
}
-// PartitionXsdSrcs partitions srcs into xsd_config modules and others
-// Since xsd_config are soong modules, we cannot use file extension for partitioning
-func PartitionXsdSrcs(ctx BazelConversionPathContext, srcs []string) ([]string, []string) {
- //isXsd returns true if src is a soong module of type xsd_config
- isXsd := func(src string) bool {
- mod, exists := ctx.ModuleFromName(src)
+// XsdModuleToTargetName is a function that takes an XsdConfigBp2buildTarget
+type XsdModuleToTargetName func(xsd XsdConfigBp2buildTargets) string
+
+// XsdLabelMapper returns a bazel.LabelMapper for partitioning XSD sources/headers given an
+// XsdModuleToTargetName function.
+func XsdLabelMapper(targetName XsdModuleToTargetName) bazel.LabelMapper {
+ return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
+ mod, exists := ctx.ModuleFromName(label.OriginalModuleName)
if !exists {
- return false
+ return label.Label, false
}
- _, _isXsd := mod.(XsdConfigBp2buildTargets)
- return _isXsd
- }
- nonXsd := []string{}
- xsd := []string{}
-
- for _, src := range srcs {
- if isXsd(src) {
- xsd = append(xsd, src)
- } else {
- nonXsd = append(nonXsd, src)
+ xsdMod, isXsd := mod.(XsdConfigBp2buildTargets)
+ if !isXsd {
+ return label.Label, false
}
- }
- return nonXsd, xsd
-}
-
-// Replaces //a/b/my_xsd_config with //a/b/my_xsd_config-{cpp|java}
-// The new target name is provided by the `targetName` callback function
-func XsdConfigBp2buildTarget(ctx BazelConversionPathContext, mod blueprint.Module, targetName func(xsd XsdConfigBp2buildTargets) string) string {
- xsd, isXsd := mod.(XsdConfigBp2buildTargets)
- if !isXsd {
- ctx.ModuleErrorf("xsdConfigJavaTarget called on %v, which is not an xsd_config", mod)
+ // Remove the base module name
+ ret := strings.TrimSuffix(label.Label, mod.Name())
+ // Append the language specific target name
+ ret += targetName(xsdMod)
+ return ret, true
}
- ret := BazelModuleLabel(ctx, mod)
- // Remove the base module name
- ret = strings.TrimSuffix(ret, mod.Name())
- // Append the language specific target name
- ret += targetName(xsd)
- return ret
}
diff --git a/android/paths.go b/android/paths.go
index fda4d2f..325a953 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -396,7 +396,7 @@
//
// Properties passed as the paths argument must have been annotated with struct tag
// `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
-// path_deps mutator.
+// pathdeps mutator.
// If a requested module is not found as a dependency:
// - if ctx.Config().AllowMissingDependencies() is true, this module to be marked as having
// missing dependencies
@@ -425,7 +425,7 @@
// excluding the items (similarly resolved
// Properties passed as the paths argument must have been annotated with struct tag
// `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
-// path_deps mutator.
+// pathdeps mutator.
// If a requested module is not found as a dependency:
// - if ctx.Config().AllowMissingDependencies() is true, this module to be marked as having
// missing dependencies
@@ -560,7 +560,7 @@
// and a list of the module names of missing module dependencies are returned as the second return.
// Properties passed as the paths argument must have been annotated with struct tag
// `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
-// path_deps mutator.
+// pathdeps mutator.
func PathsAndMissingDepsForModuleSrcExcludes(ctx ModuleMissingDepsPathContext, paths, excludes []string) (Paths, []string) {
return PathsAndMissingDepsRelativeToModuleSourceDir(SourceInput{
Context: ctx,
@@ -1029,16 +1029,16 @@
return p
}
+func (p basePath) RelativeToTop() Path {
+ ensureTestOnly()
+ return p
+}
+
// SourcePath is a Path representing a file path rooted from SrcDir
type SourcePath struct {
basePath
}
-func (p SourcePath) RelativeToTop() Path {
- ensureTestOnly()
- return p
-}
-
var _ Path = SourcePath{}
func (p SourcePath) withRel(rel string) SourcePath {
@@ -1126,6 +1126,16 @@
return path
}
+// PathForArbitraryOutput creates a path for the given components. Unlike PathForOutput,
+// the path is relative to the root of the output folder, not the out/soong folder.
+func PathForArbitraryOutput(ctx PathContext, pathComponents ...string) Path {
+ p, err := validatePath(pathComponents...)
+ if err != nil {
+ reportPathError(ctx, err)
+ }
+ return basePath{path: filepath.Join(ctx.Config().OutDir(), p)}
+}
+
// MaybeExistentPathForSource joins the provided path components and validates that the result
// neither escapes the source dir nor is in the out dir.
// It does not validate whether the path exists.
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 0438eb8..777c1cf 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -53,6 +53,7 @@
remoteable RemoteRuleSupports
rbeParams *remoteexec.REParams
outDir WritablePath
+ sboxOutSubDir string
sboxTools bool
sboxInputs bool
sboxManifestPath WritablePath
@@ -65,9 +66,18 @@
pctx: pctx,
ctx: ctx,
temporariesSet: make(map[WritablePath]bool),
+ sboxOutSubDir: sboxOutSubDir,
}
}
+// SetSboxOutDirDirAsEmpty sets the out subdirectory to an empty string
+// This is useful for sandboxing actions that change the execution root to a path in out/ (e.g mixed builds)
+// For such actions, SetSboxOutDirDirAsEmpty ensures that the path does not become $SBOX_SANDBOX_DIR/out/out/bazel/output/execroot/__main__/...
+func (rb *RuleBuilder) SetSboxOutDirDirAsEmpty() *RuleBuilder {
+ rb.sboxOutSubDir = ""
+ return rb
+}
+
// RuleBuilderInstall is a tuple of install from and to locations.
type RuleBuilderInstall struct {
From Path
@@ -585,7 +595,7 @@
for _, output := range outputs {
rel := Rel(r.ctx, r.outDir.String(), output.String())
command.CopyAfter = append(command.CopyAfter, &sbox_proto.Copy{
- From: proto.String(filepath.Join(sboxOutSubDir, rel)),
+ From: proto.String(filepath.Join(r.sboxOutSubDir, rel)),
To: proto.String(output.String()),
})
}
diff --git a/android/sdk_version_test.go b/android/sdk_version_test.go
index ea99c4d..30bd002 100644
--- a/android/sdk_version_test.go
+++ b/android/sdk_version_test.go
@@ -75,7 +75,7 @@
config := NullConfig("", "")
- config.productVariables = productVariables{
+ config.productVariables = ProductVariables{
Platform_sdk_version: intPtr(31),
Platform_sdk_codename: stringPtr("Tiramisu"),
Platform_version_active_codenames: []string{"Tiramisu"},
diff --git a/android/test_config.go b/android/test_config.go
index 28d9ec4..2a59d92 100644
--- a/android/test_config.go
+++ b/android/test_config.go
@@ -35,7 +35,7 @@
envCopy["PATH"] = os.Getenv("PATH")
config := &config{
- productVariables: productVariables{
+ productVariables: ProductVariables{
DeviceName: stringPtr("test_device"),
DeviceProduct: stringPtr("test_product"),
Platform_sdk_version: intPtr(30),
diff --git a/android/util.go b/android/util.go
index e17d7b2..5375373 100644
--- a/android/util.go
+++ b/android/util.go
@@ -137,19 +137,17 @@
}
// IndexList returns the index of the first occurrence of the given string in the list or -1
-func IndexList(s string, list []string) int {
+func IndexList[T comparable](t T, list []T) int {
for i, l := range list {
- if l == s {
+ if l == t {
return i
}
}
-
return -1
}
-// InList checks if the string belongs to the list
-func InList(s string, list []string) bool {
- return IndexList(s, list) != -1
+func InList[T comparable](t T, list []T) bool {
+ return IndexList(t, list) != -1
}
func setFromList[T comparable](l []T) map[T]bool {
diff --git a/android/variable.go b/android/variable.go
index 4442a09..7fb81b9 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -95,6 +95,10 @@
Cflags []string
}
+ Device_page_size_agnostic struct {
+ Cflags []string `android:"arch_variant"`
+ } `android:"arch_variant"`
+
Override_rs_driver struct {
Cflags []string
}
@@ -180,12 +184,19 @@
Srcs []string `android:"arch_variant"`
Exclude_srcs []string `android:"arch_variant"`
} `android:"arch_variant"`
+
+ // release_aidl_use_unfrozen is "true" when a device can
+ // use the unfrozen versions of AIDL interfaces.
+ Release_aidl_use_unfrozen struct {
+ Cflags []string
+ Cmd *string
+ }
} `android:"arch_variant"`
}
var defaultProductVariables interface{} = variableProperties{}
-type productVariables struct {
+type ProductVariables struct {
// Suffix to add to generated Makefiles
Make_suffix *string `json:",omitempty"`
@@ -275,6 +286,7 @@
Safestack *bool `json:",omitempty"`
HostStaticBinaries *bool `json:",omitempty"`
Binder32bit *bool `json:",omitempty"`
+ Device_page_size_agnostic *bool `json:",omitempty"`
UseGoma *bool `json:",omitempty"`
UseRBE *bool `json:",omitempty"`
UseRBEJAVAC *bool `json:",omitempty"`
@@ -457,6 +469,8 @@
SelinuxIgnoreNeverallows bool `json:",omitempty"`
+ Release_aidl_use_unfrozen *bool `json:",omitempty"`
+
SepolicyFreezeTestExtraDirs []string `json:",omitempty"`
SepolicyFreezeTestExtraPrebuiltDirs []string `json:",omitempty"`
@@ -475,6 +489,8 @@
ReleaseVersion string `json:",omitempty"`
ReleaseAconfigValueSets []string `json:",omitempty"`
+
+ KeepVndk *bool `json:",omitempty"`
}
func boolPtr(v bool) *bool {
@@ -489,8 +505,8 @@
return &v
}
-func (v *productVariables) SetDefaultConfig() {
- *v = productVariables{
+func (v *ProductVariables) SetDefaultConfig() {
+ *v = ProductVariables{
BuildNumberFile: stringPtr("build_number.txt"),
Platform_version_name: stringPtr("S"),
@@ -527,6 +543,7 @@
Safestack: boolPtr(false),
TrimmedApex: boolPtr(false),
Build_from_text_stub: boolPtr(false),
+ Device_page_size_agnostic: boolPtr(false),
BootJars: ConfiguredJarList{apexes: []string{}, jars: []string{}},
ApexBootJars: ConfiguredJarList{apexes: []string{}, jars: []string{}},
@@ -726,7 +743,9 @@
dst = append(dst, src...)
(*p)[propertyName][key] = dst
default:
- panic(fmt.Errorf("TODO: handle merging value %#v", existing))
+ if existing != propertyValue {
+ panic(fmt.Errorf("TODO: handle merging value %#v", existing))
+ }
}
} else {
(*p)[propertyName][key] = propertyValue
@@ -939,7 +958,7 @@
productConfigProperties.AddSoongConfigProperty(propertyName, namespace, soongConfigVariableName, soongConfigVariableValue, os.Name, property.Interface())
}
}
- } else {
+ } else if !archOrOsSpecificStruct.IsZero() {
// One problem with supporting additional fields is that if multiple branches of
// "target" overlap, we don't want them to be in the same select statement (aka
// configuration axis). "android" and "host" are disjoint, so it's ok that we only
diff --git a/apex/apex.go b/apex/apex.go
index 1d094eb..b26d1d2 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -993,7 +993,7 @@
// the non-system APEXes because the VNDK libraries won't be included (and duped) in the
// APEX, but shared across APEXes via the VNDK APEX.
useVndk := a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && mctx.Config().EnforceProductPartitionInterface())
- excludeVndkLibs := useVndk && proptools.Bool(a.properties.Use_vndk_as_stable)
+ excludeVndkLibs := useVndk && a.useVndkAsStable(mctx)
if proptools.Bool(a.properties.Use_vndk_as_stable) {
if !useVndk {
mctx.PropertyErrorf("use_vndk_as_stable", "not supported for system/system_ext APEXes")
@@ -2394,7 +2394,7 @@
// 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() {
+ if ch.UseVndk() && a.useVndkAsStable(ctx) && ch.IsVndk() {
vctx.requireNativeLibs = append(vctx.requireNativeLibs, ":vndk")
return false
}
@@ -3277,31 +3277,6 @@
// Module separator
//
m["com.android.runtime"] = []string{
- "libc_aeabi",
- "libc_bionic",
- "libc_bionic_ndk",
- "libc_bootstrap",
- "libc_common",
- "libc_common_shared",
- "libc_dns",
- "libc_dynamic_dispatch",
- "libc_fortify",
- "libc_freebsd",
- "libc_freebsd_large_stack",
- "libc_gdtoa",
- "libc_init_dynamic",
- "libc_init_static",
- "libc_jemalloc_wrapper",
- "libc_netbsd",
- "libc_nomalloc",
- "libc_nopthread",
- "libc_openbsd",
- "libc_openbsd_large_stack",
- "libc_openbsd_ndk",
- "libc_pthread",
- "libc_syscalls",
- "libc_tzcode",
- "libc_unwind_static",
"libdebuggerd",
"libdebuggerd_common_headers",
"libdebuggerd_handler_core",
@@ -3313,7 +3288,6 @@
"libprocinfo",
"libpropertyinfoparser",
"libscudo",
- "libstdc++",
"libsystemproperties",
"libtombstoned_client_static",
"libunwindstack",
@@ -3742,3 +3716,12 @@
func (a *apexBundle) IsTestApex() bool {
return a.testApex
}
+
+func (a *apexBundle) useVndkAsStable(ctx android.BaseModuleContext) bool {
+ // VNDK cannot be linked if it is deprecated
+ if ctx.Config().IsVndkDeprecated() {
+ return false
+ }
+
+ return proptools.Bool(a.properties.Use_vndk_as_stable)
+}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index df138e0..9dba08e 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -3029,7 +3029,11 @@
vendor: true,
shared_libs: ["libvndk", "libvendor"],
}
- `)
+ `,
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.TestProductVariables.KeepVndk = proptools.BoolPtr(true)
+ }),
+ )
vendorVariant := "android_vendor.29_arm64_armv8-a"
@@ -6790,6 +6794,10 @@
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
+ override_apex {
+ name: "myoverrideapex",
+ base: "bar",
+ }
`)
fooManifestRule := result.ModuleForTests("foo", "android_common_foo_image").Rule("apexManifestRule")
@@ -6806,6 +6814,12 @@
if barActualDefaultVersion != barExpectedDefaultVersion {
t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion)
}
+
+ overrideBarManifestRule := result.ModuleForTests("bar", "android_common_myoverrideapex_bar_image").Rule("apexManifestRule")
+ overrideBarActualDefaultVersion := overrideBarManifestRule.Args["default_version"]
+ if overrideBarActualDefaultVersion != barExpectedDefaultVersion {
+ t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion)
+ }
}
func TestApexAvailable_ApexAvailableName(t *testing.T) {
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 480158c..d77d59a 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -17,15 +17,15 @@
import (
"crypto/sha256"
"encoding/base64"
+ "encoding/json"
"fmt"
"path/filepath"
+ analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
"reflect"
"sort"
"strings"
"sync"
- analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
-
"github.com/google/blueprint/metrics"
"github.com/google/blueprint/proptools"
"google.golang.org/protobuf/proto"
@@ -116,6 +116,13 @@
InputDepsetHashes []string
InputPaths []string
FileContents string
+ // If ShouldRunInSbox is true, Soong will use sbox to created an isolated environment
+ // and run the mixed build action there
+ ShouldRunInSbox bool
+ // A list of files to add as implicit deps to the outputs of this BuildStatement.
+ // Unlike most properties in BuildStatement, these paths must be relative to the root of
+ // the whole out/ folder, instead of relative to ctx.Config().BazelContext.OutputBase()
+ ImplicitDeps []string
}
// A helper type for aquery processing which facilitates retrieval of path IDs from their
@@ -456,7 +463,7 @@
// escapes the args received from aquery and creates a command string
func commandString(actionEntry *analysis_v2_proto.Action) string {
switch actionEntry.Mnemonic {
- case "GoCompilePkg":
+ case "GoCompilePkg", "GoStdlib":
argsEscaped := []string{}
for _, arg := range actionEntry.Arguments {
if arg == "" {
@@ -496,6 +503,12 @@
Env: actionEntry.EnvironmentVariables,
Mnemonic: actionEntry.Mnemonic,
}
+ if buildStatement.Mnemonic == "GoToolchainBinaryBuild" {
+ // Unlike b's execution root, mixed build execution root contains a symlink to prebuilts/go
+ // This causes issues for `GOCACHE=$(mktemp -d) go build ...`
+ // To prevent this, sandbox this action in mixed builds as well
+ buildStatement.ShouldRunInSbox = true
+ }
return buildStatement, nil
}
@@ -572,6 +585,72 @@
}, nil
}
+type bazelSandwichJson struct {
+ Target string `json:"target"`
+ DependOnTarget *bool `json:"depend_on_target,omitempty"`
+ ImplicitDeps []string `json:"implicit_deps"`
+}
+
+func (a *aqueryArtifactHandler) unresolvedSymlinkActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
+ outputPaths, depfile, err := a.getOutputPaths(actionEntry)
+ if err != nil {
+ return nil, err
+ }
+ if len(actionEntry.InputDepSetIds) != 0 || len(outputPaths) != 1 {
+ return nil, fmt.Errorf("expected 0 inputs and 1 output to symlink action, got: input %q, output %q", actionEntry.InputDepSetIds, outputPaths)
+ }
+ target := actionEntry.UnresolvedSymlinkTarget
+ if target == "" {
+ return nil, fmt.Errorf("expected an unresolved_symlink_target, but didn't get one")
+ }
+ if filepath.Clean(target) != target {
+ return nil, fmt.Errorf("expected %q, got %q", filepath.Clean(target), target)
+ }
+ if strings.HasPrefix(target, "/") {
+ return nil, fmt.Errorf("no absolute symlinks allowed: %s", target)
+ }
+
+ out := outputPaths[0]
+ outDir := filepath.Dir(out)
+ var implicitDeps []string
+ if strings.HasPrefix(target, "bazel_sandwich:") {
+ j := bazelSandwichJson{}
+ err := json.Unmarshal([]byte(target[len("bazel_sandwich:"):]), &j)
+ if err != nil {
+ return nil, err
+ }
+ if proptools.BoolDefault(j.DependOnTarget, true) {
+ implicitDeps = append(implicitDeps, j.Target)
+ }
+ implicitDeps = append(implicitDeps, j.ImplicitDeps...)
+ dotDotsToReachCwd := ""
+ if outDir != "." {
+ dotDotsToReachCwd = strings.Repeat("../", strings.Count(outDir, "/")+1)
+ }
+ target = proptools.ShellEscapeIncludingSpaces(j.Target)
+ target = "{DOTDOTS_TO_OUTPUT_ROOT}" + dotDotsToReachCwd + target
+ } else {
+ target = proptools.ShellEscapeIncludingSpaces(target)
+ }
+
+ outDir = proptools.ShellEscapeIncludingSpaces(outDir)
+ out = proptools.ShellEscapeIncludingSpaces(out)
+ // Use absolute paths, because some soong actions don't play well with relative paths (for example, `cp -d`).
+ command := fmt.Sprintf("mkdir -p %[1]s && rm -f %[2]s && ln -sf %[3]s %[2]s", outDir, out, target)
+ symlinkPaths := outputPaths[:]
+
+ buildStatement := &BuildStatement{
+ Command: command,
+ Depfile: depfile,
+ OutputPaths: outputPaths,
+ Env: actionEntry.EnvironmentVariables,
+ Mnemonic: actionEntry.Mnemonic,
+ SymlinkPaths: symlinkPaths,
+ ImplicitDeps: implicitDeps,
+ }
+ return buildStatement, nil
+}
+
func (a *aqueryArtifactHandler) symlinkActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
outputPaths, depfile, err := a.getOutputPaths(actionEntry)
if err != nil {
@@ -681,6 +760,8 @@
return a.fileWriteActionBuildStatement(actionEntry)
case "SymlinkTree":
return a.symlinkTreeActionBuildStatement(actionEntry)
+ case "UnresolvedSymlink":
+ return a.unresolvedSymlinkActionBuildStatement(actionEntry)
}
if len(actionEntry.Arguments) < 1 {
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 19a584f..32c87a0 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -357,9 +357,11 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
if expected := 1; len(actual) != expected {
t.Fatalf("Expected %d build statements, got %d", expected, len(actual))
+ return
}
bs := actual[0]
@@ -544,6 +546,7 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
assertBuildStatements(t, []*BuildStatement{
&BuildStatement{
@@ -756,9 +759,11 @@
actualBuildStatements, actualDepsets, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
if expected := 2; len(actualBuildStatements) != expected {
t.Fatalf("Expected %d build statements, got %d %#v", expected, len(actualBuildStatements), actualBuildStatements)
+ return
}
expectedDepsetFiles := [][]string{
@@ -859,6 +864,7 @@
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
expectedBuildStatements := []*BuildStatement{
@@ -907,6 +913,7 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
expectedBuildStatements := []*BuildStatement{
@@ -1017,6 +1024,7 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
expectedBuildStatements := []*BuildStatement{
@@ -1088,6 +1096,7 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
assertBuildStatements(t, []*BuildStatement{
&BuildStatement{
@@ -1126,6 +1135,7 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
assertBuildStatements(t, []*BuildStatement{
&BuildStatement{
@@ -1136,6 +1146,126 @@
}, actual)
}
+func TestUnresolvedSymlink(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [
+ { "id": 1, "path_fragment_id": 1 }
+ ],
+ "actions": [{
+ "target_id": 1,
+ "action_key": "x",
+ "mnemonic": "UnresolvedSymlink",
+ "configuration_id": 1,
+ "output_ids": [1],
+ "primary_output_id": 1,
+ "execution_platform": "//build/bazel/platforms:linux_x86_64",
+ "unresolved_symlink_target": "symlink/target"
+ }],
+ "path_fragments": [
+ { "id": 1, "label": "path/to/symlink" }
+ ]
+}
+`
+ data, err := JsonToActionGraphContainer(inputString)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ return
+ }
+ assertBuildStatements(t, []*BuildStatement{{
+ Command: "mkdir -p path/to && rm -f path/to/symlink && ln -sf symlink/target path/to/symlink",
+ OutputPaths: []string{"path/to/symlink"},
+ Mnemonic: "UnresolvedSymlink",
+ SymlinkPaths: []string{"path/to/symlink"},
+ }}, actual)
+}
+
+func TestUnresolvedSymlinkBazelSandwich(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [
+ { "id": 1, "path_fragment_id": 1 }
+ ],
+ "actions": [{
+ "target_id": 1,
+ "action_key": "x",
+ "mnemonic": "UnresolvedSymlink",
+ "configuration_id": 1,
+ "output_ids": [1],
+ "primary_output_id": 1,
+ "execution_platform": "//build/bazel/platforms:linux_x86_64",
+ "unresolved_symlink_target": "bazel_sandwich:{\"target\":\"target/product/emulator_x86_64/system\"}"
+ }],
+ "path_fragments": [
+ { "id": 1, "label": "path/to/symlink" }
+ ]
+}
+`
+ data, err := JsonToActionGraphContainer(inputString)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ return
+ }
+ assertBuildStatements(t, []*BuildStatement{{
+ Command: "mkdir -p path/to && rm -f path/to/symlink && ln -sf {DOTDOTS_TO_OUTPUT_ROOT}../../target/product/emulator_x86_64/system path/to/symlink",
+ OutputPaths: []string{"path/to/symlink"},
+ Mnemonic: "UnresolvedSymlink",
+ SymlinkPaths: []string{"path/to/symlink"},
+ ImplicitDeps: []string{"target/product/emulator_x86_64/system"},
+ }}, actual)
+}
+
+func TestUnresolvedSymlinkBazelSandwichWithAlternativeDeps(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [
+ { "id": 1, "path_fragment_id": 1 }
+ ],
+ "actions": [{
+ "target_id": 1,
+ "action_key": "x",
+ "mnemonic": "UnresolvedSymlink",
+ "configuration_id": 1,
+ "output_ids": [1],
+ "primary_output_id": 1,
+ "execution_platform": "//build/bazel/platforms:linux_x86_64",
+ "unresolved_symlink_target": "bazel_sandwich:{\"depend_on_target\":false,\"implicit_deps\":[\"target/product/emulator_x86_64/obj/PACKAGING/systemimage_intermediates/staging_dir.stamp\"],\"target\":\"target/product/emulator_x86_64/system\"}"
+ }],
+ "path_fragments": [
+ { "id": 1, "label": "path/to/symlink" }
+ ]
+}
+`
+ data, err := JsonToActionGraphContainer(inputString)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ return
+ }
+ assertBuildStatements(t, []*BuildStatement{{
+ Command: "mkdir -p path/to && rm -f path/to/symlink && ln -sf {DOTDOTS_TO_OUTPUT_ROOT}../../target/product/emulator_x86_64/system path/to/symlink",
+ OutputPaths: []string{"path/to/symlink"},
+ Mnemonic: "UnresolvedSymlink",
+ SymlinkPaths: []string{"path/to/symlink"},
+ // Note that the target of the symlink, target/product/emulator_x86_64/system, is not listed here
+ ImplicitDeps: []string{"target/product/emulator_x86_64/obj/PACKAGING/systemimage_intermediates/staging_dir.stamp"},
+ }}, actual)
+}
+
func assertError(t *testing.T, err error, expected string) {
t.Helper()
if err == nil {
@@ -1201,6 +1331,9 @@
if !reflect.DeepEqual(sortedStrings(first.SymlinkPaths), sortedStrings(second.SymlinkPaths)) {
return "SymlinkPaths"
}
+ if !reflect.DeepEqual(sortedStrings(first.ImplicitDeps), sortedStrings(second.ImplicitDeps)) {
+ return "ImplicitDeps"
+ }
if first.Depfile != second.Depfile {
return "Depfile"
}
diff --git a/bazel/properties.go b/bazel/properties.go
index 15af09b..702c31c 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -288,6 +288,41 @@
return result
}
+// FirstUniqueBazelLabelListAttribute takes a LabelListAttribute and makes the LabelList for
+// each axis/configuration by keeping the first instance of a Label and omitting all subsequent
+// repetitions.
+func FirstUniqueBazelLabelListAttribute(attr LabelListAttribute) LabelListAttribute {
+ var result LabelListAttribute
+ result.Value = FirstUniqueBazelLabelList(attr.Value)
+ if attr.HasConfigurableValues() {
+ result.ConfigurableValues = make(configurableLabelLists)
+ }
+ for axis, configToLabels := range attr.ConfigurableValues {
+ for c, l := range configToLabels {
+ result.SetSelectValue(axis, c, FirstUniqueBazelLabelList(l))
+ }
+ }
+
+ return result
+}
+
+// SubtractBazelLabelListAttribute subtract needle from haystack for LabelList in each
+// axis/configuration.
+func SubtractBazelLabelListAttribute(haystack LabelListAttribute, needle LabelListAttribute) LabelListAttribute {
+ var result LabelListAttribute
+ result.Value = SubtractBazelLabelList(haystack.Value, needle.Value)
+ if haystack.HasConfigurableValues() {
+ result.ConfigurableValues = make(configurableLabelLists)
+ }
+ for axis, configToLabels := range haystack.ConfigurableValues {
+ for haystackConfig, haystackLabels := range configToLabels {
+ result.SetSelectValue(axis, haystackConfig, SubtractBazelLabelList(haystackLabels, needle.SelectValue(axis, haystackConfig)))
+ }
+ }
+
+ return result
+}
+
type Attribute interface {
HasConfigurableValues() bool
}
diff --git a/bazel/properties_test.go b/bazel/properties_test.go
index c56d11f..c98ae0e 100644
--- a/bazel/properties_test.go
+++ b/bazel/properties_test.go
@@ -125,6 +125,63 @@
}
}
}
+
+func TestSubtractBazelLabelListAttribute(t *testing.T) {
+ testCases := []struct {
+ haystack LabelListAttribute
+ needle LabelListAttribute
+ expected LabelListAttribute
+ }{
+ {
+ haystack: LabelListAttribute{
+ Value: makeLabelList(
+ []string{"a", "b", "a", "c"},
+ []string{"x", "x", "y", "z"},
+ ),
+ ConfigurableValues: configurableLabelLists{
+ ArchConfigurationAxis: labelListSelectValues{
+ "arm": makeLabelList([]string{"arm_1", "arm_2"}, []string{}),
+ "x86": makeLabelList([]string{"x86_3", "x86_4", "x86_5"}, []string{"x86_5"}),
+ },
+ },
+ },
+ needle: LabelListAttribute{
+ Value: makeLabelList(
+ []string{"d", "a"},
+ []string{"x", "y2", "z2"},
+ ),
+ ConfigurableValues: configurableLabelLists{
+ ArchConfigurationAxis: labelListSelectValues{
+ "arm": makeLabelList([]string{"arm_1", "arm_3"}, []string{}),
+ "x86": makeLabelList([]string{"x86_3", "x86_4"}, []string{"x86_6"}),
+ },
+ },
+ },
+ expected: LabelListAttribute{
+ Value: makeLabelList(
+ []string{"b", "c"},
+ []string{"x", "x", "y", "z"},
+ ),
+ ConfigurableValues: configurableLabelLists{
+ ArchConfigurationAxis: labelListSelectValues{
+ "arm": makeLabelList([]string{"arm_2"}, []string{}),
+ "x86": makeLabelList([]string{"x86_5"}, []string{"x86_5"}),
+ },
+ },
+ ForceSpecifyEmptyList: false,
+ EmitEmptyList: false,
+ Prepend: false,
+ },
+ },
+ }
+ for _, tc := range testCases {
+ got := SubtractBazelLabelListAttribute(tc.haystack, tc.needle)
+ if !reflect.DeepEqual(tc.expected, got) {
+ t.Fatalf("Expected\n%v, but got\n%v", tc.expected, got)
+ }
+ }
+}
+
func TestFirstUniqueBazelLabelList(t *testing.T) {
testCases := []struct {
originalLabelList LabelList
@@ -167,6 +224,46 @@
}
}
+func TestFirstUniqueBazelLabelListAttribute(t *testing.T) {
+ testCases := []struct {
+ originalLabelList LabelListAttribute
+ expectedUniqueLabelList LabelListAttribute
+ }{
+ {
+ originalLabelList: LabelListAttribute{
+ Value: makeLabelList(
+ []string{"a", "b", "a", "c"},
+ []string{"x", "x", "y", "z"},
+ ),
+ ConfigurableValues: configurableLabelLists{
+ ArchConfigurationAxis: labelListSelectValues{
+ "arm": makeLabelList([]string{"1", "2", "1"}, []string{}),
+ "x86": makeLabelList([]string{"3", "4", "4"}, []string{"5", "5"}),
+ },
+ },
+ },
+ expectedUniqueLabelList: LabelListAttribute{
+ Value: makeLabelList(
+ []string{"a", "b", "c"},
+ []string{"x", "y", "z"},
+ ),
+ ConfigurableValues: configurableLabelLists{
+ ArchConfigurationAxis: labelListSelectValues{
+ "arm": makeLabelList([]string{"1", "2"}, []string{}),
+ "x86": makeLabelList([]string{"3", "4"}, []string{"5"}),
+ },
+ },
+ },
+ },
+ }
+ for _, tc := range testCases {
+ actualUniqueLabelList := FirstUniqueBazelLabelListAttribute(tc.originalLabelList)
+ if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) {
+ t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList)
+ }
+ }
+}
+
func TestUniqueSortedBazelLabelList(t *testing.T) {
testCases := []struct {
originalLabelList LabelList
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index f889693..4a3786f 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -46,6 +46,7 @@
"apex_conversion_test.go",
"apex_key_conversion_test.go",
"build_conversion_test.go",
+ "bp2build_product_config_test.go",
"bzl_conversion_test.go",
"cc_binary_conversion_test.go",
"cc_library_conversion_test.go",
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index b22cb28..cfe52db 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -80,6 +80,12 @@
os.Exit(1)
}
bp2buildFiles := CreateBazelFiles(ctx.Config(), nil, res.buildFileToTargets, ctx.mode)
+ injectionFiles, additionalBp2buildFiles, err := CreateSoongInjectionDirFiles(ctx, res.metrics)
+ if err != nil {
+ fmt.Printf("%s\n", err.Error())
+ os.Exit(1)
+ }
+ bp2buildFiles = append(bp2buildFiles, additionalBp2buildFiles...)
writeFiles(ctx, bp2buildDir, bp2buildFiles)
// Delete files under the bp2build root which weren't just written. An
// alternative would have been to delete the whole directory and write these
@@ -88,11 +94,6 @@
// performance implications.
deleteFilesExcept(ctx, bp2buildDir, bp2buildFiles)
- injectionFiles, err := CreateSoongInjectionDirFiles(ctx, res.metrics)
- if err != nil {
- fmt.Printf("%s\n", err.Error())
- os.Exit(1)
- }
writeFiles(ctx, android.PathForOutput(ctx, bazel.SoongInjectionDirName), injectionFiles)
starlarkDeps, err := starlark_import.GetNinjaDeps()
if err != nil {
@@ -107,20 +108,20 @@
// This includes
// 1. config value(s) that are hardcoded in Soong
// 2. product_config variables
-func CreateSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, error) {
+func CreateSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, []BazelFile, error) {
var ret []BazelFile
- productConfigFiles, err := CreateProductConfigFiles(ctx)
+ productConfigInjectionFiles, productConfigBp2BuildDirFiles, err := CreateProductConfigFiles(ctx)
if err != nil {
- return nil, err
+ return nil, nil, err
}
- ret = append(ret, productConfigFiles...)
+ ret = append(ret, productConfigInjectionFiles...)
injectionFiles, err := soongInjectionFiles(ctx.Config(), metrics)
if err != nil {
- return nil, err
+ return nil, nil, err
}
- ret = append(ret, injectionFiles...)
- return ret, nil
+ ret = append(injectionFiles, ret...)
+ return ret, productConfigBp2BuildDirFiles, nil
}
// Get the output directory and create it if it doesn't exist.
diff --git a/bp2build/bp2build_product_config.go b/bp2build/bp2build_product_config.go
index 7224496..2513af8 100644
--- a/bp2build/bp2build_product_config.go
+++ b/bp2build/bp2build_product_config.go
@@ -1,14 +1,21 @@
package bp2build
import (
+ "android/soong/android"
+ "android/soong/starlark_import"
+ "encoding/json"
"fmt"
"os"
"path/filepath"
+ "reflect"
"strings"
+
+ "github.com/google/blueprint/proptools"
+ "go.starlark.net/starlark"
)
func CreateProductConfigFiles(
- ctx *CodegenContext) ([]BazelFile, error) {
+ ctx *CodegenContext) ([]BazelFile, []BazelFile, error) {
cfg := &ctx.config
targetProduct := "unknown"
if cfg.HasDeviceProduct() {
@@ -25,9 +32,14 @@
if !strings.HasPrefix(productVariablesFileName, "/") {
productVariablesFileName = filepath.Join(ctx.topDir, productVariablesFileName)
}
- bytes, err := os.ReadFile(productVariablesFileName)
+ productVariablesBytes, err := os.ReadFile(productVariablesFileName)
if err != nil {
- return nil, err
+ return nil, nil, err
+ }
+ productVariables := android.ProductVariables{}
+ err = json.Unmarshal(productVariablesBytes, &productVariables)
+ if err != nil {
+ return nil, nil, err
}
// TODO(b/249685973): the name is product_config_platforms because product_config
@@ -39,11 +51,16 @@
"{VARIANT}", targetBuildVariant,
"{PRODUCT_FOLDER}", currentProductFolder)
- result := []BazelFile{
+ platformMappingContent, err := platformMappingContent(productReplacer.Replace("@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"), &productVariables)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ injectionDirFiles := []BazelFile{
newFile(
currentProductFolder,
"soong.variables.bzl",
- `variables = json.decode("""`+strings.ReplaceAll(string(bytes), "\\", "\\\\")+`""")`),
+ `variables = json.decode("""`+strings.ReplaceAll(string(productVariablesBytes), "\\", "\\\\")+`""")`),
newFile(
currentProductFolder,
"BUILD",
@@ -80,6 +97,7 @@
android_product(
name = "mixed_builds_product-{VARIANT}",
soong_variables = _soong_variables,
+ extra_constraints = ["@//build/bazel/platforms:mixed_builds"],
)
`)),
newFile(
@@ -99,6 +117,7 @@
"product_config_platforms",
"common.bazelrc",
productReplacer.Replace(`
+build --platform_mappings=platform_mappings
build --platforms @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
build:android --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}
@@ -120,6 +139,148 @@
build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_darwin_x86_64
`)),
}
+ bp2buildDirFiles := []BazelFile{
+ newFile(
+ "",
+ "platform_mappings",
+ platformMappingContent),
+ }
+ return injectionDirFiles, bp2buildDirFiles, nil
+}
+
+func platformMappingContent(mainProductLabel string, mainProductVariables *android.ProductVariables) (string, error) {
+ productsForTesting, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing")
+ if err != nil {
+ return "", err
+ }
+ var result strings.Builder
+ result.WriteString("platforms:\n")
+ platformMappingSingleProduct(mainProductLabel, mainProductVariables, &result)
+ for product, productVariablesStarlark := range productsForTesting {
+ productVariables, err := starlarkMapToProductVariables(productVariablesStarlark)
+ if err != nil {
+ return "", err
+ }
+ platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables, &result)
+ }
+ return result.String(), nil
+}
+
+var bazelPlatformSuffixes = []string{
+ "",
+ "_darwin_arm64",
+ "_darwin_x86_64",
+ "_linux_bionic_arm64",
+ "_linux_bionic_x86_64",
+ "_linux_musl_x86",
+ "_linux_musl_x86_64",
+ "_linux_x86",
+ "_linux_x86_64",
+ "_windows_x86",
+ "_windows_x86_64",
+}
+
+func platformMappingSingleProduct(label string, productVariables *android.ProductVariables, result *strings.Builder) {
+ targetBuildVariant := "user"
+ if proptools.Bool(productVariables.Eng) {
+ targetBuildVariant = "eng"
+ } else if proptools.Bool(productVariables.Debuggable) {
+ targetBuildVariant = "userdebug"
+ }
+
+ for _, suffix := range bazelPlatformSuffixes {
+ result.WriteString(" ")
+ result.WriteString(label)
+ result.WriteString(suffix)
+ result.WriteString("\n")
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:always_use_prebuilt_sdks=%t\n", proptools.Bool(productVariables.Always_use_prebuilt_sdks)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:apex_global_min_sdk_version_override=%s\n", proptools.String(productVariables.ApexGlobalMinSdkVersionOverride)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_id=%s\n", proptools.String(productVariables.BuildId)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_version_tags=%s\n", strings.Join(productVariables.BuildVersionTags, ",")))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:certificate_overrides=%s\n", strings.Join(productVariables.CertificateOverrides, ",")))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:cfi_exclude_paths=%s\n", strings.Join(productVariables.CFIExcludePaths, ",")))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:cfi_include_paths=%s\n", strings.Join(productVariables.CFIIncludePaths, ",")))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:compressed_apex=%t\n", proptools.Bool(productVariables.CompressedApex)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:default_app_certificate=%s\n", proptools.String(productVariables.DefaultAppCertificate)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_abi=%s\n", strings.Join(productVariables.DeviceAbi, ",")))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_max_page_size_supported=%s\n", proptools.String(productVariables.DeviceMaxPageSizeSupported)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_name=%s\n", proptools.String(productVariables.DeviceName)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_product=%s\n", proptools.String(productVariables.DeviceProduct)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:enable_cfi=%t\n", proptools.BoolDefault(productVariables.EnableCFI, true)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:manifest_package_name_overrides=%s\n", strings.Join(productVariables.ManifestPackageNameOverrides, ",")))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:platform_version_name=%s\n", proptools.String(productVariables.Platform_version_name)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:product_brand=%s\n", productVariables.ProductBrand))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:product_manufacturer=%s\n", productVariables.ProductManufacturer))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:target_build_variant=%s\n", targetBuildVariant))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:tidy_checks=%s\n", proptools.String(productVariables.TidyChecks)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:unbundled_build=%t\n", proptools.Bool(productVariables.Unbundled_build)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:unbundled_build_apps=%s\n", strings.Join(productVariables.Unbundled_build_apps, ",")))
+ }
+}
+
+func starlarkMapToProductVariables(in map[string]starlark.Value) (android.ProductVariables, error) {
+ result := android.ProductVariables{}
+ productVarsReflect := reflect.ValueOf(&result).Elem()
+ for i := 0; i < productVarsReflect.NumField(); i++ {
+ field := productVarsReflect.Field(i)
+ fieldType := productVarsReflect.Type().Field(i)
+ name := fieldType.Name
+ if name == "BootJars" || name == "ApexBootJars" || name == "VendorVars" ||
+ name == "VendorSnapshotModules" || name == "RecoverySnapshotModules" {
+ // These variables have more complicated types, and we don't need them right now
+ continue
+ }
+ if _, ok := in[name]; ok {
+ switch field.Type().Kind() {
+ case reflect.Bool:
+ val, err := starlark_import.Unmarshal[bool](in[name])
+ if err != nil {
+ return result, err
+ }
+ field.SetBool(val)
+ case reflect.String:
+ val, err := starlark_import.Unmarshal[string](in[name])
+ if err != nil {
+ return result, err
+ }
+ field.SetString(val)
+ case reflect.Slice:
+ if field.Type().Elem().Kind() != reflect.String {
+ return result, fmt.Errorf("slices of types other than strings are unimplemented")
+ }
+ val, err := starlark_import.UnmarshalReflect(in[name], field.Type())
+ if err != nil {
+ return result, err
+ }
+ field.Set(val)
+ case reflect.Pointer:
+ switch field.Type().Elem().Kind() {
+ case reflect.Bool:
+ val, err := starlark_import.UnmarshalNoneable[bool](in[name])
+ if err != nil {
+ return result, err
+ }
+ field.Set(reflect.ValueOf(val))
+ case reflect.String:
+ val, err := starlark_import.UnmarshalNoneable[string](in[name])
+ if err != nil {
+ return result, err
+ }
+ field.Set(reflect.ValueOf(val))
+ case reflect.Int:
+ val, err := starlark_import.UnmarshalNoneable[int](in[name])
+ if err != nil {
+ return result, err
+ }
+ field.Set(reflect.ValueOf(val))
+ default:
+ return result, fmt.Errorf("pointers of types other than strings/bools are unimplemented: %s", field.Type().Elem().Kind().String())
+ }
+ default:
+ return result, fmt.Errorf("unimplemented type: %s", field.Type().String())
+ }
+ }
+ }
return result, nil
}
diff --git a/bp2build/bp2build_product_config_test.go b/bp2build/bp2build_product_config_test.go
new file mode 100644
index 0000000..3dd53ce
--- /dev/null
+++ b/bp2build/bp2build_product_config_test.go
@@ -0,0 +1,88 @@
+package bp2build
+
+import (
+ "android/soong/android"
+ "android/soong/starlark_import"
+ "encoding/json"
+ "reflect"
+ "testing"
+
+ "github.com/google/blueprint/proptools"
+ "go.starlark.net/starlark"
+)
+
+func createStarlarkValue(t *testing.T, code string) starlark.Value {
+ t.Helper()
+ result, err := starlark.ExecFile(&starlark.Thread{}, "main.bzl", "x = "+code, nil)
+ if err != nil {
+ t.Error(err)
+ }
+ return result["x"]
+}
+
+func createStarlarkProductVariablesMap(t *testing.T, code string) map[string]starlark.Value {
+ t.Helper()
+ rawValue := createStarlarkValue(t, code)
+ value, err := starlark_import.Unmarshal[map[string]starlark.Value](rawValue)
+ if err != nil {
+ t.Error(err)
+ }
+ return value
+}
+
+func TestStarlarkMapToProductVariables(t *testing.T) {
+ thirty := 30
+ cases := []struct {
+ starlark string
+ result android.ProductVariables
+ }{
+ {
+ starlark: `{"CompressedApex": True}`,
+ result: android.ProductVariables{CompressedApex: proptools.BoolPtr(true)},
+ },
+ {
+ starlark: `{"ApexGlobalMinSdkVersionOverride": "Tiramisu"}`,
+ result: android.ProductVariables{ApexGlobalMinSdkVersionOverride: proptools.StringPtr("Tiramisu")},
+ },
+ {
+ starlark: `{"ProductManufacturer": "Google"}`,
+ result: android.ProductVariables{ProductManufacturer: "Google"},
+ },
+ {
+ starlark: `{"Unbundled_build_apps": ["app1", "app2"]}`,
+ result: android.ProductVariables{Unbundled_build_apps: []string{"app1", "app2"}},
+ },
+ {
+ starlark: `{"Platform_sdk_version": 30}`,
+ result: android.ProductVariables{Platform_sdk_version: &thirty},
+ },
+ {
+ starlark: `{"HostFakeSnapshotEnabled": True}`,
+ result: android.ProductVariables{HostFakeSnapshotEnabled: true},
+ },
+ }
+
+ for _, testCase := range cases {
+ productVariables, err := starlarkMapToProductVariables(createStarlarkProductVariablesMap(t,
+ testCase.starlark))
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(testCase.result, productVariables) {
+ expected, err := json.Marshal(testCase.result)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ actual, err := json.Marshal(productVariables)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ expectedStr := string(expected)
+ actualStr := string(actual)
+ t.Errorf("expected %q, but got %q", expectedStr, actualStr)
+ }
+ }
+}
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index a817386..09a9d04 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -353,7 +353,104 @@
Importpath bazel.StringAttribute
Srcs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
+ Data bazel.LabelListAttribute
Target_compatible_with bazel.LabelListAttribute
+
+ // attributes for the dynamically generated go_test target
+ Embed bazel.LabelListAttribute
+}
+
+type goTestProperties struct {
+ name string
+ dir string
+ testSrcs []string
+ linuxTestSrcs []string
+ darwinTestSrcs []string
+ testData []string
+ // Name of the target that should be compiled together with the test
+ embedName string
+}
+
+// Creates a go_test target for bootstrap_go_package / blueprint_go_binary
+func generateBazelTargetsGoTest(ctx *android.Context, goModulesMap nameToGoLibraryModule, gp goTestProperties) (BazelTarget, error) {
+ ca := android.CommonAttributes{
+ Name: gp.name,
+ }
+ ga := goAttributes{
+ Srcs: goSrcLabels(ctx.Config(), gp.dir, gp.testSrcs, gp.linuxTestSrcs, gp.darwinTestSrcs),
+ Data: goSrcLabels(ctx.Config(), gp.dir, gp.testData, []string{}, []string{}),
+ Embed: bazel.MakeLabelListAttribute(
+ bazel.MakeLabelList(
+ []bazel.Label{bazel.Label{Label: ":" + gp.embedName}},
+ ),
+ ),
+ Target_compatible_with: targetNotCompatibleWithAndroid(),
+ }
+
+ libTest := goBazelTarget{
+ targetName: gp.name,
+ targetPackage: gp.dir,
+ bazelRuleClass: "go_test",
+ bazelRuleLoadLocation: "@io_bazel_rules_go//go:def.bzl",
+ bazelAttributes: []interface{}{&ca, &ga},
+ }
+ return generateBazelTarget(ctx, libTest)
+}
+
+// TODO - b/288491147: testSrcs of certain bootstrap_go_package/blueprint_go_binary are not hermetic and depend on
+// testdata checked into the filesystem.
+// Denylist the generation of go_test targets for these Soong modules.
+// The go_library/go_binary will still be generated, since those are hermitic.
+var (
+ goTestsDenylist = []string{
+ "android-archive-zip",
+ "bazel_notice_gen",
+ "blueprint-bootstrap-bpdoc",
+ "blueprint-microfactory",
+ "blueprint-pathtools",
+ "bssl_ar",
+ "compliance_checkmetadata",
+ "compliance_checkshare",
+ "compliance_dumpgraph",
+ "compliance_dumpresolutions",
+ "compliance_listshare",
+ "compliance-module",
+ "compliancenotice_bom",
+ "compliancenotice_shippedlibs",
+ "compliance_rtrace",
+ "compliance_sbom",
+ "golang-protobuf-internal-fuzz-jsonfuzz",
+ "golang-protobuf-internal-fuzz-textfuzz",
+ "golang-protobuf-internal-fuzz-wirefuzz",
+ "htmlnotice",
+ "protoc-gen-go",
+ "rbcrun-module",
+ "spdx-tools-builder",
+ "spdx-tools-builder2v1",
+ "spdx-tools-builder2v2",
+ "spdx-tools-builder2v3",
+ "spdx-tools-idsearcher",
+ "spdx-tools-spdx-json",
+ "spdx-tools-utils",
+ "soong-ui-build",
+ "textnotice",
+ "xmlnotice",
+ }
+)
+
+func testOfGoPackageIsIncompatible(g *bootstrap.GoPackage) bool {
+ return android.InList(g.Name(), goTestsDenylist) ||
+ // Denylist tests of soong_build
+ // Theses tests have a guard that prevent usage outside a test environment
+ // The guard (`ensureTestOnly`) looks for a `-test` in os.Args, which is present in soong's gotestrunner, but missing in `b test`
+ g.IsPluginFor("soong_build") ||
+ // soong-android is a dep of soong_build
+ // This dependency is created by soong_build by listing it in its deps explicitly in Android.bp, and not via `plugin_for` in `soong-android`
+ g.Name() == "soong-android"
+}
+
+func testOfGoBinaryIsIncompatible(g *bootstrap.GoBinary) bool {
+ return android.InList(g.Name(), goTestsDenylist)
}
func generateBazelTargetsGoPackage(ctx *android.Context, g *bootstrap.GoPackage, goModulesMap nameToGoLibraryModule) ([]BazelTarget, []error) {
@@ -390,12 +487,33 @@
bazelRuleLoadLocation: "@io_bazel_rules_go//go:def.bzl",
bazelAttributes: []interface{}{&ca, &ga},
}
- // TODO - b/284483729: Create go_test target from testSrcs
- libTarget, err := generateBazelTarget(ctx, lib)
- if err != nil {
- return []BazelTarget{}, []error{err}
+ retTargets := []BazelTarget{}
+ var retErrs []error
+ if libTarget, err := generateBazelTarget(ctx, lib); err == nil {
+ retTargets = append(retTargets, libTarget)
+ } else {
+ retErrs = []error{err}
}
- return []BazelTarget{libTarget}, nil
+
+ // If the library contains test srcs, create an additional go_test target
+ if !testOfGoPackageIsIncompatible(g) && (len(g.TestSrcs()) > 0 || len(g.LinuxTestSrcs()) > 0 || len(g.DarwinTestSrcs()) > 0) {
+ gp := goTestProperties{
+ name: g.Name() + "-test",
+ dir: ctx.ModuleDir(g),
+ testSrcs: g.TestSrcs(),
+ linuxTestSrcs: g.LinuxTestSrcs(),
+ darwinTestSrcs: g.DarwinTestSrcs(),
+ testData: g.TestData(),
+ embedName: g.Name(), // embed the source go_library in the test so that its .go files are included in the compilation unit
+ }
+ if libTestTarget, err := generateBazelTargetsGoTest(ctx, goModulesMap, gp); err == nil {
+ retTargets = append(retTargets, libTestTarget)
+ } else {
+ retErrs = append(retErrs, err)
+ }
+ }
+
+ return retTargets, retErrs
}
type goLibraryModule struct {
@@ -440,6 +558,9 @@
Name: g.Name(),
}
+ retTargets := []BazelTarget{}
+ var retErrs []error
+
// For this bootstrap_go_package dep chain,
// A --> B --> C ( ---> depends on)
// Soong provides the convenience of only listing B as deps of A even if a src file of A imports C
@@ -450,12 +571,70 @@
// bp2build does not have sufficient info on whether C is a direct dep of A or not, so for now collect all transitive deps and add them to deps
transitiveDeps := transitiveGoDeps(g.Deps(), goModulesMap)
+ goSource := ""
+ // If the library contains test srcs, create an additional go_test target
+ // The go_test target will embed a go_source containining the source .go files it tests
+ if !testOfGoBinaryIsIncompatible(g) && (len(g.TestSrcs()) > 0 || len(g.LinuxTestSrcs()) > 0 || len(g.DarwinTestSrcs()) > 0) {
+ // Create a go_source containing the source .go files of go_library
+ // This target will be an `embed` of the go_binary and go_test
+ goSource = g.Name() + "-source"
+ ca := android.CommonAttributes{
+ Name: goSource,
+ }
+ ga := goAttributes{
+ Srcs: goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs()),
+ Deps: goDepLabels(transitiveDeps, goModulesMap),
+ Target_compatible_with: targetNotCompatibleWithAndroid(),
+ }
+ libTestSource := goBazelTarget{
+ targetName: goSource,
+ targetPackage: ctx.ModuleDir(g),
+ bazelRuleClass: "go_source",
+ bazelRuleLoadLocation: "@io_bazel_rules_go//go:def.bzl",
+ bazelAttributes: []interface{}{&ca, &ga},
+ }
+ if libSourceTarget, err := generateBazelTarget(ctx, libTestSource); err == nil {
+ retTargets = append(retTargets, libSourceTarget)
+ } else {
+ retErrs = append(retErrs, err)
+ }
+
+ // Create a go_test target
+ gp := goTestProperties{
+ name: g.Name() + "-test",
+ dir: ctx.ModuleDir(g),
+ testSrcs: g.TestSrcs(),
+ linuxTestSrcs: g.LinuxTestSrcs(),
+ darwinTestSrcs: g.DarwinTestSrcs(),
+ testData: g.TestData(),
+ // embed the go_source in the test
+ embedName: g.Name() + "-source",
+ }
+ if libTestTarget, err := generateBazelTargetsGoTest(ctx, goModulesMap, gp); err == nil {
+ retTargets = append(retTargets, libTestTarget)
+ } else {
+ retErrs = append(retErrs, err)
+ }
+
+ }
+
+ // Create a go_binary target
ga := goAttributes{
- Srcs: goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs()),
Deps: goDepLabels(transitiveDeps, goModulesMap),
Target_compatible_with: targetNotCompatibleWithAndroid(),
}
+ // If the binary has testSrcs, embed the common `go_source`
+ if goSource != "" {
+ ga.Embed = bazel.MakeLabelListAttribute(
+ bazel.MakeLabelList(
+ []bazel.Label{bazel.Label{Label: ":" + goSource}},
+ ),
+ )
+ } else {
+ ga.Srcs = goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs())
+ }
+
bin := goBazelTarget{
targetName: g.Name(),
targetPackage: ctx.ModuleDir(g),
@@ -463,24 +642,15 @@
bazelRuleLoadLocation: "@io_bazel_rules_go//go:def.bzl",
bazelAttributes: []interface{}{&ca, &ga},
}
- // TODO - b/284483729: Create go_test target from testSrcs
- binTarget, err := generateBazelTarget(ctx, bin)
- if err != nil {
- return []BazelTarget{}, []error{err}
- }
- return []BazelTarget{binTarget}, nil
-}
-var (
- // TODO - b/284483729: Remove this denyilst
- // Temporary denylist of go binaries that are currently used in mixed builds
- // This denylist allows us to rollout bp2build converters for go targets without affecting mixed builds
- goBinaryDenylist = []string{
- "soong_zip",
- "zip2zip",
- "bazel_notice_gen",
+ if binTarget, err := generateBazelTarget(ctx, bin); err == nil {
+ retTargets = append(retTargets, binTarget)
+ } else {
+ retErrs = []error{err}
}
-)
+
+ return retTargets, retErrs
+}
func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (conversionResults, []error) {
buildFileToTargets := make(map[string]BazelTargets)
@@ -574,10 +744,12 @@
targets, targetErrs = generateBazelTargetsGoPackage(bpCtx, glib, nameToGoLibMap)
errs = append(errs, targetErrs...)
metrics.IncrementRuleClassCount("go_library")
- } else if gbin, ok := m.(*bootstrap.GoBinary); ok && !android.InList(m.Name(), goBinaryDenylist) {
+ metrics.AddConvertedModule(glib, "go_library", dir)
+ } else if gbin, ok := m.(*bootstrap.GoBinary); ok {
targets, targetErrs = generateBazelTargetsGoBinary(bpCtx, gbin, nameToGoLibMap)
errs = append(errs, targetErrs...)
metrics.IncrementRuleClassCount("go_binary")
+ metrics.AddConvertedModule(gbin, "go_binary", dir)
} else {
metrics.AddUnconvertedModule(m, moduleType, dir, android.UnconvertedReason{
ReasonType: int(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED),
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index 4b36cc7..d9a7860 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -1214,3 +1214,82 @@
},
})
}
+
+func TestCcBinaryStatic_SystemSharedLibUsedAsDep(t *testing.T) {
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+ description: "cc_library_static system_shared_lib empty for linux_bionic variant",
+ blueprint: soongCcLibraryStaticPreamble +
+ simpleModuleDoNotConvertBp2build("cc_library", "libc") + `
+
+cc_library {
+ name: "libm",
+ bazel_module: { bp2build_available: false },
+}
+
+cc_binary {
+ name: "used_in_bionic_oses",
+ target: {
+ android: {
+ static_libs: ["libc"],
+ },
+ linux_bionic: {
+ static_libs: ["libc"],
+ },
+ },
+ include_build_directory: false,
+ static_executable: true,
+}
+
+cc_binary {
+ name: "all",
+ static_libs: ["libc"],
+ include_build_directory: false,
+ static_executable: true,
+}
+
+cc_binary {
+ name: "keep_for_empty_system_shared_libs",
+ static_libs: ["libc"],
+ system_shared_libs: [],
+ include_build_directory: false,
+ static_executable: true,
+}
+
+cc_binary {
+ name: "used_with_stubs",
+ static_libs: ["libm"],
+ include_build_directory: false,
+ static_executable: true,
+}
+
+cc_binary {
+ name: "keep_with_stubs",
+ static_libs: ["libm"],
+ system_shared_libs: [],
+ include_build_directory: false,
+ static_executable: true,
+}
+`,
+ targets: []testBazelTarget{
+ {"cc_binary", "all", AttrNameToString{
+ "linkshared": "False",
+ }},
+ {"cc_binary", "keep_for_empty_system_shared_libs", AttrNameToString{
+ "deps": `[":libc_bp2build_cc_library_static"]`,
+ "system_deps": `[]`,
+ "linkshared": "False",
+ }},
+ {"cc_binary", "keep_with_stubs", AttrNameToString{
+ "linkshared": "False",
+ "deps": `[":libm_bp2build_cc_library_static"]`,
+ "system_deps": `[]`,
+ }},
+ {"cc_binary", "used_in_bionic_oses", AttrNameToString{
+ "linkshared": "False",
+ }},
+ {"cc_binary", "used_with_stubs", AttrNameToString{
+ "linkshared": "False",
+ }},
+ },
+ })
+}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 8084a5d..03e9cd0 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1003,6 +1003,38 @@
})
}
+func TestCcLibraryStaticGeneratedHeadersMultipleExports(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Blueprint: soongCcLibraryStaticPreamble + `
+genrule {
+ name: "generated_hdr",
+ cmd: "nothing to see here",
+ export_include_dirs: ["foo", "bar"],
+ bazel_module: { bp2build_available: false },
+}
+
+genrule {
+ name: "export_generated_hdr",
+ cmd: "nothing to see here",
+ export_include_dirs: ["a", "b"],
+ bazel_module: { bp2build_available: false },
+}
+
+cc_library_static {
+ name: "foo_static",
+ generated_headers: ["generated_hdr", "export_generated_hdr"],
+ export_generated_headers: ["export_generated_hdr"],
+ include_build_directory: false,
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
+ "deps": `[":export_generated_hdr__header_library"]`,
+ "implementation_deps": `[":generated_hdr__header_library"]`,
+ }),
+ },
+ })
+}
+
// generated_headers has "variant_prepend" tag. In bp2build output,
// variant info(select) should go before general info.
func TestCcLibraryStaticArchSrcsExcludeSrcsGeneratedFiles(t *testing.T) {
diff --git a/bp2build/cc_test_conversion_test.go b/bp2build/cc_test_conversion_test.go
index 4df4d4d..3c037b4 100644
--- a/bp2build/cc_test_conversion_test.go
+++ b/bp2build/cc_test_conversion_test.go
@@ -94,7 +94,9 @@
simpleModuleDoNotConvertBp2build("genrule", "data_mod") +
simpleModuleDoNotConvertBp2build("cc_binary", "cc_bin") +
simpleModuleDoNotConvertBp2build("cc_library", "cc_lib") +
- simpleModuleDoNotConvertBp2build("cc_test_library", "cc_test_lib2"),
+ simpleModuleDoNotConvertBp2build("cc_test_library", "cc_test_lib2") +
+ simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
+ simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
targets: []testBazelTarget{
{"cc_library_shared", "cc_test_lib1", AttrNameToString{}},
{"cc_library_static", "cc_test_lib1_bp2build_cc_library_static", AttrNameToString{}},
@@ -106,7 +108,11 @@
":cc_bin",
":cc_lib",
]`,
- "deps": `[":cc_test_lib1_bp2build_cc_library_static"] + select({
+ "deps": `[
+ ":cc_test_lib1_bp2build_cc_library_static",
+ ":libgtest_main",
+ ":libgtest",
+ ] + select({
"//build/bazel/platforms/os:darwin": [":hostlib"],
"//build/bazel/platforms/os:linux_bionic": [":hostlib"],
"//build/bazel/platforms/os:linux_glibc": [":hostlib"],
@@ -114,8 +120,6 @@
"//build/bazel/platforms/os:windows": [":hostlib"],
"//conditions:default": [],
})`,
- "gtest": "True",
- "isolated": "True",
"local_includes": `["."]`,
"dynamic_deps": `[":cc_test_lib2"] + select({
"//build/bazel/platforms/os:android": [":foolib"],
@@ -152,7 +156,6 @@
targets: []testBazelTarget{
{"cc_test", "mytest", AttrNameToString{
"gtest": "False",
- "isolated": "False",
"local_includes": `["."]`,
"srcs": `["test.cpp"]`,
},
@@ -171,14 +174,17 @@
srcs: ["test.cpp"],
test_options: { tags: ["no-remote"] },
}
-`,
+` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
+ simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
targets: []testBazelTarget{
{"cc_test", "mytest", AttrNameToString{
"tags": `["no-remote"]`,
"local_includes": `["."]`,
"srcs": `["test.cpp"]`,
- "gtest": "True",
- "isolated": "True",
+ "deps": `[
+ ":libgtest_main",
+ ":libgtest",
+ ]`,
},
},
},
@@ -197,15 +203,18 @@
srcs: ["test.cpp"],
test_config: "test_config.xml",
}
-`,
+` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
+ simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
targets: []testBazelTarget{
{"cc_test", "mytest", AttrNameToString{
- "gtest": "True",
- "isolated": "True",
"local_includes": `["."]`,
"srcs": `["test.cpp"]`,
"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
"test_config": `"test_config.xml"`,
+ "deps": `[
+ ":libgtest_main",
+ ":libgtest",
+ ]`,
},
},
},
@@ -223,15 +232,18 @@
name: "mytest",
srcs: ["test.cpp"],
}
-`,
+` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
+ simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
targets: []testBazelTarget{
{"cc_test", "mytest", AttrNameToString{
- "gtest": "True",
- "isolated": "True",
"local_includes": `["."]`,
"srcs": `["test.cpp"]`,
"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
"test_config": `"AndroidTest.xml"`,
+ "deps": `[
+ ":libgtest_main",
+ ":libgtest",
+ ]`,
},
},
},
@@ -250,13 +262,13 @@
srcs: ["test.cpp"],
test_config_template: "test_config_template.xml",
auto_gen_config: true,
+ isolated: true,
}
-`,
+` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_isolated_main") +
+ simpleModuleDoNotConvertBp2build("cc_library", "liblog"),
targets: []testBazelTarget{
{"cc_test", "mytest", AttrNameToString{
"auto_generate_test_config": "True",
- "gtest": "True",
- "isolated": "True",
"local_includes": `["."]`,
"srcs": `["test.cpp"]`,
"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
@@ -266,6 +278,95 @@
]`,
"template_install_base": `"/data/local/tmp"`,
"template_test_config": `"test_config_template.xml"`,
+ "deps": `[":libgtest_isolated_main"]`,
+ "dynamic_deps": `[":liblog"]`,
+ },
+ },
+ },
+ })
+}
+
+func TestCcTest_WithExplicitGTestDepInAndroidBp(t *testing.T) {
+ runCcTestTestCase(t, ccTestBp2buildTestCase{
+ description: "cc test that lists libgtest in Android.bp should not have dups of libgtest in BUILD file",
+ blueprint: `
+cc_test {
+ name: "mytest",
+ srcs: ["test.cpp"],
+ static_libs: ["libgtest"],
+}
+` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
+ simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
+ targets: []testBazelTarget{
+ {"cc_test", "mytest", AttrNameToString{
+ "local_includes": `["."]`,
+ "srcs": `["test.cpp"]`,
+ "target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+ "deps": `[
+ ":libgtest",
+ ":libgtest_main",
+ ]`,
+ },
+ },
+ },
+ })
+
+}
+
+func TestCcTest_WithIsolatedTurnedOn(t *testing.T) {
+ runCcTestTestCase(t, ccTestBp2buildTestCase{
+ description: "cc test that sets `isolated: true` should run with ligtest_isolated_main instead of libgtest_main",
+ blueprint: `
+cc_test {
+ name: "mytest",
+ srcs: ["test.cpp"],
+ isolated: true,
+}
+` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_isolated_main") +
+ simpleModuleDoNotConvertBp2build("cc_library", "liblog"),
+ targets: []testBazelTarget{
+ {"cc_test", "mytest", AttrNameToString{
+ "local_includes": `["."]`,
+ "srcs": `["test.cpp"]`,
+ "target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+ "deps": `[":libgtest_isolated_main"]`,
+ "dynamic_deps": `[":liblog"]`,
+ },
+ },
+ },
+ })
+
+}
+
+func TestCcTest_GtestExplicitlySpecifiedInAndroidBp(t *testing.T) {
+ runCcTestTestCase(t, ccTestBp2buildTestCase{
+ description: "If `gtest` is explicit in Android.bp, it should be explicit in BUILD files as well",
+ blueprint: `
+cc_test {
+ name: "mytest_with_gtest",
+ gtest: true,
+}
+cc_test {
+ name: "mytest_with_no_gtest",
+ gtest: false,
+}
+` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
+ simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
+ targets: []testBazelTarget{
+ {"cc_test", "mytest_with_gtest", AttrNameToString{
+ "local_includes": `["."]`,
+ "deps": `[
+ ":libgtest_main",
+ ":libgtest",
+ ]`,
+ "gtest": "True",
+ "target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+ },
+ },
+ {"cc_test", "mytest_with_no_gtest", AttrNameToString{
+ "local_includes": `["."]`,
+ "gtest": "False",
+ "target_compatible_with": `["//build/bazel/platforms/os:android"]`,
},
},
},
diff --git a/bp2build/genrule_conversion_test.go b/bp2build/genrule_conversion_test.go
index 5cf4fb2..5a73969 100644
--- a/bp2build/genrule_conversion_test.go
+++ b/bp2build/genrule_conversion_test.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "path/filepath"
"testing"
"android/soong/android"
@@ -695,3 +696,79 @@
})
})
}
+
+func TestGenruleWithExportIncludeDirs(t *testing.T) {
+ testCases := []struct {
+ moduleType string
+ factory android.ModuleFactory
+ hod android.HostOrDeviceSupported
+ }{
+ {
+ moduleType: "genrule",
+ factory: genrule.GenRuleFactory,
+ },
+ {
+ moduleType: "cc_genrule",
+ factory: cc.GenRuleFactory,
+ hod: android.DeviceSupported,
+ },
+ {
+ moduleType: "java_genrule",
+ factory: java.GenRuleFactory,
+ hod: android.DeviceSupported,
+ },
+ {
+ moduleType: "java_genrule_host",
+ factory: java.GenRuleFactoryHost,
+ hod: android.HostSupported,
+ },
+ }
+
+ dir := "baz"
+
+ bp := `%s {
+ name: "foo",
+ out: ["foo.out.h"],
+ srcs: ["foo.in"],
+ cmd: "cp $(in) $(out)",
+ export_include_dirs: ["foo", "bar", "."],
+ bazel_module: { bp2build_available: true },
+}`
+
+ for _, tc := range testCases {
+ moduleAttrs := AttrNameToString{
+ "cmd": `"cp $(SRCS) $(OUTS)"`,
+ "outs": `["foo.out.h"]`,
+ "srcs": `["foo.in"]`,
+ }
+
+ expectedBazelTargets := []string{
+ makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
+ makeBazelTargetHostOrDevice("cc_library_headers", "foo__header_library", AttrNameToString{
+ "hdrs": `[":foo"]`,
+ "export_includes": `[
+ "foo",
+ "baz/foo",
+ "bar",
+ "baz/bar",
+ ".",
+ "baz",
+ ]`,
+ },
+ tc.hod),
+ }
+
+ t.Run(tc.moduleType, func(t *testing.T) {
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+ Bp2buildTestCase{
+ ModuleTypeUnderTest: tc.moduleType,
+ ModuleTypeUnderTestFactory: tc.factory,
+ Filesystem: map[string]string{
+ filepath.Join(dir, "Android.bp"): fmt.Sprintf(bp, tc.moduleType),
+ },
+ Dir: dir,
+ ExpectedBazelTargets: expectedBazelTargets,
+ })
+ })
+ }
+}
diff --git a/bp2build/go_conversion_test.go b/bp2build/go_conversion_test.go
index 507fbf0..2387641 100644
--- a/bp2build/go_conversion_test.go
+++ b/bp2build/go_conversion_test.go
@@ -45,11 +45,17 @@
srcs: [
"foo_linux.go",
],
+ testSrcs: [
+ "foo_linux_test.go",
+ ],
},
darwin: {
srcs: [
"foo_darwin.go",
],
+ testSrcs: [
+ "foo_darwin_test.go",
+ ],
},
testSrcs: [
"foo1_test.go",
@@ -84,7 +90,21 @@
})`,
},
android.HostSupported,
- )},
+ ),
+ makeBazelTargetHostOrDevice("go_test", "foo-test",
+ AttrNameToString{
+ "embed": `[":foo"]`,
+ "srcs": `[
+ "foo1_test.go",
+ "foo2_test.go",
+ ] + select({
+ "//build/bazel/platforms/os:darwin": ["foo_darwin_test.go"],
+ "//build/bazel/platforms/os:linux_glibc": ["foo_linux_test.go"],
+ "//conditions:default": [],
+ })`,
+ },
+ android.HostSupported,
+ )},
})
}
@@ -125,6 +145,44 @@
})
}
+func TestConvertGoBinaryWithTestSrcs(t *testing.T) {
+ bp := `
+blueprint_go_binary {
+ name: "foo",
+ srcs: ["main.go"],
+ testSrcs: ["main_test.go"],
+}
+`
+ t.Parallel()
+ runGoTests(t, Bp2buildTestCase{
+ Description: "Convert blueprint_go_binary with testSrcs",
+ Blueprint: bp,
+ ExpectedBazelTargets: []string{
+ makeBazelTargetHostOrDevice("go_binary", "foo",
+ AttrNameToString{
+ "deps": `[]`,
+ "embed": `[":foo-source"]`,
+ },
+ android.HostSupported,
+ ),
+ makeBazelTargetHostOrDevice("go_source", "foo-source",
+ AttrNameToString{
+ "deps": `[]`,
+ "srcs": `["main.go"]`,
+ },
+ android.HostSupported,
+ ),
+ makeBazelTargetHostOrDevice("go_test", "foo-test",
+ AttrNameToString{
+ "embed": `[":foo-source"]`,
+ "srcs": `["main_test.go"]`,
+ },
+ android.HostSupported,
+ ),
+ },
+ })
+}
+
func TestConvertGoBinaryWithSrcInDifferentPackage(t *testing.T) {
bp := `
blueprint_go_binary {
diff --git a/bp2build/java_test_host_conversion_test.go b/bp2build/java_test_host_conversion_test.go
index f411ffb..f41345e 100644
--- a/bp2build/java_test_host_conversion_test.go
+++ b/bp2build/java_test_host_conversion_test.go
@@ -71,6 +71,11 @@
}),
MakeBazelTarget("java_test", "java_test_host-1", AttrNameToString{
"runtime_deps": `[":java_test_host-1_lib"]`,
+ "deps": `[
+ ":lib_a-neverlink",
+ ":static_libs_a",
+ ]`,
+ "srcs": `["a.java"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
@@ -128,6 +133,10 @@
`,
ExpectedBazelTargets: []string{
MakeBazelTarget("java_test", "java_test_host-1", AttrNameToString{
+ "srcs": `[
+ "a.java",
+ "b.kt",
+ ]`,
"runtime_deps": `[":java_test_host-1_lib"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go
index 813773d..143597d 100644
--- a/bp2build/soong_config_module_type_conversion_test.go
+++ b/bp2build/soong_config_module_type_conversion_test.go
@@ -1406,3 +1406,111 @@
target_compatible_with = ["//build/bazel/platforms/os:android"],
)`}})
}
+
+// If we have
+// A. a soong_config_module_type with target.android_<arch>.* in properties
+// B. a module that uses this module type but does not set target.android_<arch>.* via soong config vars
+// Then we should not panic
+func TestPanicsIfSoongConfigModuleTypeHasArchSpecificProperties(t *testing.T) {
+ commonBp := `
+soong_config_bool_variable {
+ name: "my_bool_variable",
+}
+soong_config_module_type {
+ name: "special_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "my_namespace",
+ bool_variables: ["my_bool_variable"],
+ properties: [
+ "cflags",
+ "target.android_arm64.shared_libs",
+ ],
+}
+cc_binary {
+ name: "my_binary",
+ defaults: ["my_special_cc_defaults"],
+}
+`
+ testCases := []struct {
+ desc string
+ additionalBp string
+ isPanicExpected bool
+ }{
+ {
+ desc: "target.android_arm64 is not set, bp2build should not panic",
+ additionalBp: `
+special_cc_defaults {
+ name: "my_special_cc_defaults",
+ soong_config_variables: {
+ my_bool_variable: {
+ cflags: ["-DFOO"],
+ conditions_default: {
+ cflags: ["-DBAR"],
+ }
+ }
+ },
+}
+ `,
+ isPanicExpected: false,
+ },
+ {
+ desc: "target.android_arm64 is set using the bool soong config var, bp2build should panic",
+ additionalBp: `
+special_cc_defaults {
+ name: "my_special_cc_defaults",
+ soong_config_variables: {
+ my_bool_variable: {
+ cflags: ["-DFOO"],
+ target: {
+ android_arm64: {
+ shared_libs: ["liblog"],
+ },
+ },
+ conditions_default: {
+ cflags: ["-DBAR"],
+ }
+ }
+ },
+}
+ `,
+ isPanicExpected: true,
+ },
+ {
+ desc: "target.android_arm64 is set using conditions_default for the bool soong config var, bp2build should panic",
+ additionalBp: `
+special_cc_defaults {
+ name: "my_special_cc_defaults",
+ soong_config_variables: {
+ my_bool_variable: {
+ cflags: ["-DFOO"],
+ conditions_default: {
+ cflags: ["-DBAR"],
+ target: {
+ android_arm64: {
+ shared_libs: ["liblog"],
+ },
+ },
+ }
+ }
+ },
+}
+ `,
+ isPanicExpected: true,
+ },
+ }
+ for _, tc := range testCases {
+ bp2buildTestCase := Bp2buildTestCase{
+ Description: tc.desc,
+ ModuleTypeUnderTest: "cc_binary",
+ ModuleTypeUnderTestFactory: cc.BinaryFactory,
+ Blueprint: commonBp + tc.additionalBp,
+ // Check in `foo` dir so that we can check whether it panics or not and not trip over an empty `ExpectedBazelTargets`
+ Dir: "foo",
+ ExpectedBazelTargets: []string{},
+ }
+ if tc.isPanicExpected {
+ bp2buildTestCase.ExpectedErr = fmt.Errorf("TODO: support other target types in soong config variable structs: Android_arm64")
+ }
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase)
+ }
+}
diff --git a/cc/Android.bp b/cc/Android.bp
index f49dc1a..e88ea03 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -32,6 +32,7 @@
"check.go",
"coverage.go",
"gen.go",
+ "generated_cc_library.go",
"image.go",
"linkable.go",
"lto.go",
diff --git a/cc/afdo.go b/cc/afdo.go
index bc7cd52..23d196d 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -131,6 +131,10 @@
return
}
+ if !c.afdo.afdoEnabled() {
+ return
+ }
+
ctx.VisitDirectDepsWithTag(FdoProfileTag, func(m android.Module) {
if ctx.OtherModuleHasProvider(m, FdoProfileProvider) {
info := ctx.OtherModuleProvider(m, FdoProfileProvider).(FdoProfileInfo)
diff --git a/cc/api_level.go b/cc/api_level.go
index a5571f3..69a0d3a 100644
--- a/cc/api_level.go
+++ b/cc/api_level.go
@@ -31,7 +31,11 @@
case android.Arm64, android.X86_64:
return android.FirstLp64Version
case android.Riscv64:
- return android.FutureApiLevel
+ apiLevel, err := android.ApiLevelFromUser(ctx, "VanillaIceCream")
+ if err != nil {
+ panic(err)
+ }
+ return apiLevel
default:
panic(fmt.Errorf("Unknown arch %q", arch))
}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 85a2284..9e485d6 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -22,6 +22,7 @@
"android/soong/android"
"android/soong/bazel"
"android/soong/cc/config"
+ "android/soong/genrule"
"github.com/google/blueprint"
@@ -43,6 +44,12 @@
rScriptSrcPartition = "renderScript"
+ xsdSrcPartition = "xsd"
+
+ genrulePartition = "genrule"
+
+ hdrPartition = "hdr"
+
stubsSuffix = "_stub_libs_current"
)
@@ -155,6 +162,7 @@
lSrcPartition: bazel.LabelPartition{Extensions: []string{".l"}},
llSrcPartition: bazel.LabelPartition{Extensions: []string{".ll"}},
rScriptSrcPartition: bazel.LabelPartition{Extensions: []string{".fs", ".rscript"}},
+ xsdSrcPartition: bazel.LabelPartition{LabelMapper: android.XsdLabelMapper(xsdConfigCppTarget)},
// C++ is the "catch-all" group, and comprises generated sources because we don't
// know the language of these sources until the genrule is executed.
cppSrcPartition: bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true},
@@ -165,6 +173,15 @@
return bazel.PartitionLabelListAttribute(ctx, &srcs, labels)
}
+func partitionHeaders(ctx android.BazelConversionPathContext, hdrs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute {
+ labels := bazel.LabelPartitions{
+ xsdSrcPartition: bazel.LabelPartition{LabelMapper: android.XsdLabelMapper(xsdConfigCppTarget)},
+ genrulePartition: bazel.LabelPartition{LabelMapper: genrule.GenruleCcHeaderLabelMapper},
+ hdrPartition: bazel.LabelPartition{Keep_remainder: true},
+ }
+ return bazel.PartitionLabelListAttribute(ctx, &hdrs, labels)
+}
+
// bp2BuildParseLibProps returns the attributes for a variant of a cc_library.
func bp2BuildParseLibProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) staticOrSharedAttributes {
lib, ok := module.compiler.(*libraryDecorator)
@@ -403,7 +420,12 @@
srcs bazel.LabelListAttribute
// xsd config sources
- xsdInSrcs bazel.StringListAttribute
+ xsdSrcs bazel.LabelListAttribute
+ exportXsdSrcs bazel.LabelListAttribute
+
+ // genrule headers
+ genruleHeaders bazel.LabelListAttribute
+ exportGenruleHeaders bazel.LabelListAttribute
// Lex sources and options
lSrcs bazel.LabelListAttribute
@@ -494,14 +516,11 @@
func (ca *compilerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis, config string, props *BaseCompilerProperties) {
// If there's arch specific srcs or exclude_srcs, generate a select entry for it.
// TODO(b/186153868): do this for OS specific srcs and exclude_srcs too.
- srcsList, xsdList, ok := parseSrcs(ctx, props)
+ srcsList, ok := parseSrcs(ctx, props)
if ok {
ca.srcs.SetSelectValue(axis, config, srcsList)
}
- if len(xsdList) > 0 {
- ca.xsdInSrcs.SetSelectValue(axis, config, xsdList)
- }
localIncludeDirs := props.Local_include_dirs
if axis == bazel.NoConfigAxis {
@@ -568,9 +587,11 @@
}
}
-func (ca *compilerAttributes) finalize(ctx android.BazelConversionPathContext, implementationHdrs bazel.LabelListAttribute) {
+func (ca *compilerAttributes) finalize(ctx android.BazelConversionPathContext, implementationHdrs, exportHdrs bazel.LabelListAttribute) {
ca.srcs.ResolveExcludes()
partitionedSrcs := groupSrcsByExtension(ctx, ca.srcs)
+ partitionedImplHdrs := partitionHeaders(ctx, implementationHdrs)
+ partitionedHdrs := partitionHeaders(ctx, exportHdrs)
ca.protoSrcs = partitionedSrcs[protoSrcPartition]
ca.aidlSrcs = partitionedSrcs[aidlSrcPartition]
@@ -580,10 +601,22 @@
if lla.IsEmpty() {
continue
}
- lla.Append(implementationHdrs)
+ lla.Append(partitionedImplHdrs[hdrPartition])
partitionedSrcs[p] = lla
}
+ ca.hdrs = partitionedHdrs[hdrPartition]
+
+ ca.includesFromHeaders(ctx, partitionedImplHdrs[hdrPartition], partitionedHdrs[hdrPartition])
+
+ xsdSrcs := bazel.SubtractBazelLabelListAttribute(partitionedSrcs[xsdSrcPartition], partitionedHdrs[xsdSrcPartition])
+ xsdSrcs.Append(partitionedImplHdrs[xsdSrcPartition])
+ ca.exportXsdSrcs = partitionedHdrs[xsdSrcPartition]
+ ca.xsdSrcs = bazel.FirstUniqueBazelLabelListAttribute(xsdSrcs)
+
+ ca.genruleHeaders = partitionedImplHdrs[genrulePartition]
+ ca.exportGenruleHeaders = partitionedHdrs[genrulePartition]
+
ca.srcs = partitionedSrcs[cppSrcPartition]
ca.cSrcs = partitionedSrcs[cSrcPartition]
ca.asSrcs = partitionedSrcs[asSrcPartition]
@@ -604,11 +637,11 @@
}
// Parse srcs from an arch or OS's props value.
-func parseSrcs(ctx android.BazelConversionPathContext, props *BaseCompilerProperties) (bazel.LabelList, []string, bool) {
+func parseSrcs(ctx android.BazelConversionPathContext, props *BaseCompilerProperties) (bazel.LabelList, bool) {
anySrcs := false
// Add srcs-like dependencies such as generated files.
// First create a LabelList containing these dependencies, then merge the values with srcs.
- genSrcs, xsd := android.PartitionXsdSrcs(ctx, props.Generated_sources)
+ genSrcs := props.Generated_sources
generatedSrcsLabelList := android.BazelLabelForModuleDepsExcludes(ctx, genSrcs, props.Exclude_generated_sources)
if len(props.Generated_sources) > 0 || len(props.Exclude_generated_sources) > 0 {
anySrcs = true
@@ -620,7 +653,7 @@
anySrcs = true
}
- return bazel.AppendBazelLabelLists(allSrcsLabelList, generatedSrcsLabelList), xsd, anySrcs
+ return bazel.AppendBazelLabelLists(allSrcsLabelList, generatedSrcsLabelList), anySrcs
}
func bp2buildStdVal(std *string, prefix string, useGnu bool) *string {
@@ -667,8 +700,43 @@
return split[0][2:], true
}
-// includesFromLabelList extracts relative/absolute includes from a bazel.LabelList>
-func includesFromLabelList(labelList bazel.LabelList) (relative, absolute []string) {
+// includesFromHeaders gets the include directories needed from generated headers
+func (ca *compilerAttributes) includesFromHeaders(ctx android.BazelConversionPathContext, implHdrs, hdrs bazel.LabelListAttribute) {
+ local, absolute := includesFromLabelListAttribute(implHdrs, ca.localIncludes, ca.absoluteIncludes)
+ localExport, absoluteExport := includesFromLabelListAttribute(hdrs, ca.includes.Includes, ca.includes.AbsoluteIncludes)
+
+ ca.localIncludes = local
+ ca.absoluteIncludes = absolute
+
+ ca.includes.Includes = localExport
+ ca.includes.AbsoluteIncludes = absoluteExport
+}
+
+// includesFromLabelList extracts the packages from a LabelListAttribute that should be includes and
+// combines them with existing local/absolute includes.
+func includesFromLabelListAttribute(attr bazel.LabelListAttribute, existingLocal, existingAbsolute bazel.StringListAttribute) (bazel.StringListAttribute, bazel.StringListAttribute) {
+ localAttr := existingLocal.Clone()
+ absoluteAttr := existingAbsolute.Clone()
+ if !attr.Value.IsEmpty() {
+ l, a := includesFromLabelList(attr.Value, existingLocal.Value, existingAbsolute.Value)
+ localAttr.SetSelectValue(bazel.NoConfigAxis, "", l)
+ absoluteAttr.SetSelectValue(bazel.NoConfigAxis, "", a)
+ }
+ for axis, configToLabels := range attr.ConfigurableValues {
+ for c, labels := range configToLabels {
+ local := existingLocal.SelectValue(axis, c)
+ absolute := existingAbsolute.SelectValue(axis, c)
+ l, a := includesFromLabelList(labels, local, absolute)
+ localAttr.SetSelectValue(axis, c, l)
+ absoluteAttr.SetSelectValue(axis, c, a)
+ }
+ }
+ return *localAttr, *absoluteAttr
+}
+
+// includesFromLabelList extracts relative/absolute includes from a bazel.LabelList.
+func includesFromLabelList(labelList bazel.LabelList, existingRel, existingAbs []string) ([]string, []string) {
+ var relative, absolute []string
for _, hdr := range labelList.Includes {
if pkg, hasPkg := packageFromLabel(hdr.Label); hasPkg {
absolute = append(absolute, pkg)
@@ -676,6 +744,12 @@
relative = append(relative, pkg)
}
}
+ if len(relative)+len(existingRel) != 0 {
+ relative = android.FirstUniqueStrings(append(append([]string{}, existingRel...), relative...))
+ }
+ if len(absolute)+len(existingAbs) != 0 {
+ absolute = android.FirstUniqueStrings(append(append([]string{}, existingAbs...), absolute...))
+ }
return relative, absolute
}
@@ -740,8 +814,6 @@
archVariantLinkerProps := module.GetArchVariantProperties(ctx, &BaseLinkerProperties{})
archVariantLibraryProperties := module.GetArchVariantProperties(ctx, &LibraryProperties{})
- var implementationHdrs bazel.LabelListAttribute
-
axisToConfigs := map[bazel.ConfigurationAxis]map[string]bool{}
allAxesAndConfigs := func(cp android.ConfigurationAxisToArchVariantProperties) {
for axis, configMap := range cp {
@@ -761,6 +833,7 @@
linkerAttrs := linkerAttributes{}
var aidlLibs bazel.LabelList
+ var implementationHdrs, exportHdrs bazel.LabelListAttribute
// Iterate through these axes in a deterministic order. This is required
// because processing certain dependencies may result in concatenating
@@ -770,9 +843,9 @@
for _, axis := range bazel.SortedConfigurationAxes(axisToConfigs) {
configs := axisToConfigs[axis]
for cfg := range configs {
- var allHdrs, allHdrsXsd []string
+ var allHdrs []string
if baseCompilerProps, ok := archVariantCompilerProps[axis][cfg].(*BaseCompilerProperties); ok {
- allHdrs, allHdrsXsd = android.PartitionXsdSrcs(ctx, baseCompilerProps.Generated_headers)
+ allHdrs = baseCompilerProps.Generated_headers
if baseCompilerProps.Lex != nil {
compilerAttrs.lexopts.SetSelectValue(axis, cfg, baseCompilerProps.Lex.Flags)
@@ -786,36 +859,17 @@
aidlLibs.Append(android.BazelLabelForModuleDeps(ctx, baseCompilerProps.Aidl.Libs))
}
- var exportHdrs, exportHdrsXsd []string
+ var exportedHdrs []string
if baseLinkerProps, ok := archVariantLinkerProps[axis][cfg].(*BaseLinkerProperties); ok {
- exportHdrs, exportHdrsXsd = android.PartitionXsdSrcs(ctx, baseLinkerProps.Export_generated_headers)
+ exportedHdrs = baseLinkerProps.Export_generated_headers
(&linkerAttrs).bp2buildForAxisAndConfig(ctx, module, axis, cfg, baseLinkerProps)
}
- // in the synthetic bp2build workspace, xsd sources are compiled to a static library
- xsdList := compilerAttrs.xsdInSrcs.SelectValue(axis, cfg)
- allHdrsXsd = android.FirstUniqueStrings(append(xsdList, allHdrsXsd...))
- headers := maybePartitionExportedAndImplementationsDeps(ctx, !module.Binary(), allHdrs, exportHdrs, android.BazelLabelForModuleDeps)
- xsdConfigLibs := maybePartitionExportedAndImplementationsDeps(ctx, !module.Binary(), allHdrsXsd, exportHdrsXsd, bazelLabelForXsdConfig)
+ headers := maybePartitionExportedAndImplementationsDeps(ctx, !module.Binary(), allHdrs, exportedHdrs, android.BazelLabelForModuleDeps)
implementationHdrs.SetSelectValue(axis, cfg, headers.implementation)
- compilerAttrs.hdrs.SetSelectValue(axis, cfg, headers.export)
-
- exportIncludes, exportAbsoluteIncludes := includesFromLabelList(headers.export)
- compilerAttrs.includes.Includes.SetSelectValue(axis, cfg, exportIncludes)
- compilerAttrs.includes.AbsoluteIncludes.SetSelectValue(axis, cfg, exportAbsoluteIncludes)
-
- includes, absoluteIncludes := includesFromLabelList(headers.implementation)
- currAbsoluteIncludes := compilerAttrs.absoluteIncludes.SelectValue(axis, cfg)
- currAbsoluteIncludes = android.FirstUniqueStrings(append(currAbsoluteIncludes, absoluteIncludes...))
-
- compilerAttrs.absoluteIncludes.SetSelectValue(axis, cfg, currAbsoluteIncludes)
-
- currIncludes := compilerAttrs.localIncludes.SelectValue(axis, cfg)
- currIncludes = android.FirstUniqueStrings(append(currIncludes, includes...))
-
- compilerAttrs.localIncludes.SetSelectValue(axis, cfg, currIncludes)
+ exportHdrs.SetSelectValue(axis, cfg, headers.export)
if libraryProps, ok := archVariantLibraryProperties[axis][cfg].(*LibraryProperties); ok {
if axis == bazel.NoConfigAxis {
@@ -835,14 +889,6 @@
}
}
- if len(allHdrsXsd) > 0 {
- wholeStaticLibs := linkerAttrs.implementationWholeArchiveDeps.SelectValue(axis, cfg)
- (&wholeStaticLibs).Append(xsdConfigLibs.implementation)
- linkerAttrs.implementationWholeArchiveDeps.SetSelectValue(axis, cfg, wholeStaticLibs)
- wholeStaticLibs = linkerAttrs.wholeArchiveDeps.SelectValue(axis, cfg)
- (&wholeStaticLibs).Append(xsdConfigLibs.export)
- linkerAttrs.wholeArchiveDeps.SetSelectValue(axis, cfg, wholeStaticLibs)
- }
}
}
@@ -860,11 +906,17 @@
(&compilerAttrs).convertProductVariables(ctx, productVariableProps)
(&linkerAttrs).convertProductVariables(ctx, productVariableProps)
- (&compilerAttrs).finalize(ctx, implementationHdrs)
+ (&compilerAttrs).finalize(ctx, implementationHdrs, exportHdrs)
(&linkerAttrs).finalize(ctx)
(&compilerAttrs.srcs).Add(bp2BuildYasm(ctx, module, compilerAttrs))
+ (&linkerAttrs).deps.Append(compilerAttrs.exportGenruleHeaders)
+ (&linkerAttrs).implementationDeps.Append(compilerAttrs.genruleHeaders)
+
+ (&linkerAttrs).wholeArchiveDeps.Append(compilerAttrs.exportXsdSrcs)
+ (&linkerAttrs).implementationWholeArchiveDeps.Append(compilerAttrs.xsdSrcs)
+
protoDep := bp2buildProto(ctx, module, compilerAttrs.protoSrcs)
// bp2buildProto will only set wholeStaticLib or implementationWholeStaticLib, but we don't know
@@ -1139,6 +1191,7 @@
wholeArchiveDeps bazel.LabelListAttribute
implementationWholeArchiveDeps bazel.LabelListAttribute
systemDynamicDeps bazel.LabelListAttribute
+ usedSystemDynamicDepAsStaticDep map[string]bool
usedSystemDynamicDepAsDynamicDep map[string]bool
useVersionLib bazel.BoolAttribute
@@ -1201,6 +1254,18 @@
// https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=247-249;drc=088b53577dde6e40085ffd737a1ae96ad82fc4b0
la.wholeArchiveDeps.SetSelectValue(axis, config, bazelLabelForWholeDepsExcludes(ctx, wholeStaticLibs, props.Exclude_static_libs))
+ if isBinary && module.StaticExecutable() {
+ usedSystemStatic := android.FilterListPred(staticLibs, func(s string) bool {
+ return android.InList(s, soongSystemSharedLibs) && !android.InList(s, props.Exclude_static_libs)
+ })
+
+ for _, el := range usedSystemStatic {
+ if la.usedSystemDynamicDepAsStaticDep == nil {
+ la.usedSystemDynamicDepAsStaticDep = map[string]bool{}
+ }
+ la.usedSystemDynamicDepAsStaticDep[el] = true
+ }
+ }
staticDeps := maybePartitionExportedAndImplementationsDepsExcludes(
ctx,
!isBinary,
@@ -1233,6 +1298,7 @@
usedSystem := android.FilterListPred(sharedLibs, func(s string) bool {
return android.InList(s, soongSystemSharedLibs) && !android.InList(s, excludeSharedLibs)
})
+
for _, el := range usedSystem {
if la.usedSystemDynamicDepAsDynamicDep == nil {
la.usedSystemDynamicDepAsDynamicDep = map[string]bool{}
@@ -1625,6 +1691,15 @@
}
la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidPlatform, bazel.MakeLabelList(stubsToRemove))
}
+ if la.systemDynamicDeps.IsNil() && len(la.usedSystemDynamicDepAsStaticDep) > 0 {
+ toRemove := bazelLabelForStaticDeps(ctx, android.SortedKeys(la.usedSystemDynamicDepAsStaticDep))
+ la.deps.Exclude(bazel.NoConfigAxis, "", toRemove)
+ la.deps.Exclude(bazel.OsConfigurationAxis, "android", toRemove)
+ la.deps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove)
+ la.implementationDeps.Exclude(bazel.NoConfigAxis, "", toRemove)
+ la.implementationDeps.Exclude(bazel.OsConfigurationAxis, "android", toRemove)
+ la.implementationDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove)
+ }
la.deps.ResolveExcludes()
la.implementationDeps.ResolveExcludes()
@@ -1725,16 +1800,8 @@
return label
}
-// Replaces //a/b/my_xsd_config with //a/b/my_xsd_config-cpp
-func xsdConfigCppTarget(ctx android.BazelConversionPathContext, mod blueprint.Module) string {
- callback := func(xsd android.XsdConfigBp2buildTargets) string {
- return xsd.CppBp2buildTargetName()
- }
- return android.XsdConfigBp2buildTarget(ctx, mod, callback)
-}
-
-func bazelLabelForXsdConfig(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
- return android.BazelLabelForModuleDepsWithFn(ctx, modules, xsdConfigCppTarget)
+func xsdConfigCppTarget(xsd android.XsdConfigBp2buildTargets) string {
+ return xsd.CppBp2buildTargetName()
}
func bazelLabelForWholeDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
diff --git a/cc/cc.go b/cc/cc.go
index c13f7c9..be67286 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -42,6 +42,7 @@
func init() {
RegisterCCBuildComponents(android.InitRegistrationContext)
+ pctx.Import("android/soong/android")
pctx.Import("android/soong/cc/config")
}
@@ -568,6 +569,24 @@
props() []interface{}
}
+// Information returned from Generator about the source code it's generating
+type GeneratedSource struct {
+ IncludeDirs android.Paths
+ Sources android.Paths
+ Headers android.Paths
+ ReexportedDirs android.Paths
+}
+
+// generator allows injection of generated code
+type Generator interface {
+ GeneratorProps() []interface{}
+ GeneratorInit(ctx BaseModuleContext)
+ GeneratorDeps(ctx DepsContext, deps Deps) Deps
+ GeneratorFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags
+ GeneratorSources(ctx ModuleContext) GeneratedSource
+ GeneratorBuildActions(ctx ModuleContext, flags Flags, deps PathDeps)
+}
+
// compiler is the interface for a compiler helper object. Different module decorators may implement
// this helper differently.
type compiler interface {
@@ -850,6 +869,7 @@
// type-specific logic. These members may reference different objects or the same object.
// Functions of these decorators will be invoked to initialize and register type-specific
// build statements.
+ generators []Generator
compiler compiler
linker linker
installer installer
@@ -1200,6 +1220,9 @@
func (c *Module) Init() android.Module {
c.AddProperties(&c.Properties, &c.VendorProperties)
+ for _, generator := range c.generators {
+ c.AddProperties(generator.GeneratorProps()...)
+ }
if c.compiler != nil {
c.AddProperties(c.compiler.compilerProps()...)
}
@@ -1371,7 +1394,7 @@
func (c *Module) isCfi() bool {
if sanitize := c.sanitize; sanitize != nil {
- return Bool(sanitize.Properties.Sanitize.Cfi)
+ return Bool(sanitize.Properties.SanitizeMutated.Cfi)
}
return false
}
@@ -2148,6 +2171,25 @@
return
}
+ for _, generator := range c.generators {
+ gen := generator.GeneratorSources(ctx)
+ deps.IncludeDirs = append(deps.IncludeDirs, gen.IncludeDirs...)
+ deps.ReexportedDirs = append(deps.ReexportedDirs, gen.ReexportedDirs...)
+ deps.GeneratedDeps = append(deps.GeneratedDeps, gen.Headers...)
+ deps.ReexportedGeneratedHeaders = append(deps.ReexportedGeneratedHeaders, gen.Headers...)
+ deps.ReexportedDeps = append(deps.ReexportedDeps, gen.Headers...)
+ if len(deps.Objs.objFiles) == 0 {
+ // If we are reusuing object files (which happens when we're a shared library and we're
+ // reusing our static variant's object files), then skip adding the actual source files,
+ // because we already have the object for it.
+ deps.GeneratedSources = append(deps.GeneratedSources, gen.Sources...)
+ }
+ }
+
+ if ctx.Failed() {
+ return
+ }
+
if c.stubLibraryMultipleApexViolation(actx) {
actx.PropertyErrorf("apex_available",
"Stub libraries should have a single apex_available (test apexes excluded). Got %v", c.ApexAvailable())
@@ -2162,6 +2204,9 @@
Toolchain: c.toolchain(ctx),
EmitXrefs: ctx.Config().EmitXrefRules(),
}
+ for _, generator := range c.generators {
+ flags = generator.GeneratorFlags(ctx, flags, deps)
+ }
if c.compiler != nil {
flags = c.compiler.compilerFlags(ctx, flags, deps)
}
@@ -2219,6 +2264,10 @@
flags.AssemblerWithCpp = inList("-xassembler-with-cpp", flags.Local.AsFlags)
+ for _, generator := range c.generators {
+ generator.GeneratorBuildActions(ctx, flags, deps)
+ }
+
var objs Objects
if c.compiler != nil {
objs = c.compiler.compile(ctx, flags, deps)
@@ -2306,6 +2355,9 @@
}
func (c *Module) begin(ctx BaseModuleContext) {
+ for _, generator := range c.generators {
+ generator.GeneratorInit(ctx)
+ }
if c.compiler != nil {
c.compiler.compilerInit(ctx)
}
@@ -2341,6 +2393,9 @@
func (c *Module) deps(ctx DepsContext) Deps {
deps := Deps{}
+ for _, generator := range c.generators {
+ deps = generator.GeneratorDeps(ctx, deps)
+ }
if c.compiler != nil {
deps = c.compiler.compilerDeps(ctx, deps)
}
@@ -2949,20 +3004,20 @@
ctx.ModuleErrorf("links %q built against newer API version %q",
ctx.OtherModuleName(to.Module()), "current")
} else {
- fromApi, err := strconv.Atoi(from.SdkVersion())
+ fromApi, err := android.ApiLevelFromUserWithConfig(ctx.Config(), from.SdkVersion())
if err != nil {
ctx.PropertyErrorf("sdk_version",
- "Invalid sdk_version value (must be int or current): %q",
+ "Invalid sdk_version value (must be int, preview or current): %q",
from.SdkVersion())
}
- toApi, err := strconv.Atoi(to.SdkVersion())
+ toApi, err := android.ApiLevelFromUserWithConfig(ctx.Config(), to.SdkVersion())
if err != nil {
ctx.PropertyErrorf("sdk_version",
- "Invalid sdk_version value (must be int or current): %q",
+ "Invalid sdk_version value (must be int, preview or current): %q",
to.SdkVersion())
}
- if toApi > fromApi {
+ if toApi.GreaterThan(fromApi) {
ctx.ModuleErrorf("links %q built against newer API version %q",
ctx.OtherModuleName(to.Module()), to.SdkVersion())
}
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 7534db2..d95ed3f 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -3261,7 +3261,7 @@
},
},
LabelToCcBinary: map[string]cquery.CcUnstrippedInfo{
- "//:test": cquery.CcUnstrippedInfo{
+ "//:test__tf_internal": cquery.CcUnstrippedInfo{
CcAndroidMkInfo: tc.androidMkInfo,
},
"//:binary": cquery.CcUnstrippedInfo{
diff --git a/cc/compiler.go b/cc/compiler.go
index 16f4a6e..5bed8a7 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -189,13 +189,13 @@
// build the recovery variant of the C/C++ module.
Exclude_generated_sources []string
}
- Vendor_ramdisk struct {
+ Ramdisk, Vendor_ramdisk struct {
// list of source files that should not be used to
- // build the vendor ramdisk variant of the C/C++ module.
+ // build the ramdisk variants of the C/C++ module.
Exclude_srcs []string `android:"path"`
- // List of additional cflags that should be used to build the vendor ramdisk
- // variant of the C/C++ module.
+ // List of additional cflags that should be used to build the ramdisk
+ // variants of the C/C++ module.
Cflags []string
}
Platform struct {
@@ -351,6 +351,7 @@
CheckBadCompilerFlags(ctx, "vendor.cflags", compiler.Properties.Target.Vendor.Cflags)
CheckBadCompilerFlags(ctx, "product.cflags", compiler.Properties.Target.Product.Cflags)
CheckBadCompilerFlags(ctx, "recovery.cflags", compiler.Properties.Target.Recovery.Cflags)
+ CheckBadCompilerFlags(ctx, "ramdisk.cflags", compiler.Properties.Target.Ramdisk.Cflags)
CheckBadCompilerFlags(ctx, "vendor_ramdisk.cflags", compiler.Properties.Target.Vendor_ramdisk.Cflags)
CheckBadCompilerFlags(ctx, "platform.cflags", compiler.Properties.Target.Platform.Cflags)
@@ -536,6 +537,9 @@
if ctx.inVendorRamdisk() {
flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Vendor_ramdisk.Cflags)...)
}
+ if ctx.inRamdisk() {
+ flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Ramdisk.Cflags)...)
+ }
if !ctx.useSdk() {
flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Platform.Cflags)...)
}
diff --git a/cc/config/global.go b/cc/config/global.go
index 266d278..ff5ab05 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -149,6 +149,7 @@
commonGlobalLldflags = []string{
"-fuse-ld=lld",
"-Wl,--icf=safe",
+ "-Wl,--no-demangle",
}
deviceGlobalCppflags = []string{
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index a0ef575..62f75d1 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -261,5 +261,3 @@
func LibFuzzerRuntimeInterceptors(t Toolchain) string {
return LibclangRuntimeLibrary(t, "fuzzer_interceptors")
}
-
-var inList = android.InList
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index dd612ce..f9b3eac 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -21,6 +21,7 @@
var VndkMustUseVendorVariantList = []string{
"android.hardware.nfc@1.2",
"libbinder",
+ "libdumpstateutil",
"libcrypto",
"libexpat",
"libgatekeeper",
diff --git a/cc/coverage.go b/cc/coverage.go
index c0f6973..cbd8a6f 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -48,6 +48,7 @@
func getGcovProfileLibraryName(ctx ModuleContextIntf) string {
// This function should only ever be called for a cc.Module, so the
// following statement should always succeed.
+ // LINT.IfChange
if ctx.useSdk() {
return "libprofile-extras_ndk"
} else {
@@ -63,6 +64,7 @@
} else {
return "libprofile-clang-extras"
}
+ // LINT.ThenChange(library.go)
}
func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps {
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 636ad85..227fe8b 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -29,6 +29,7 @@
func init() {
android.RegisterModuleType("cc_fuzz", LibFuzzFactory)
android.RegisterParallelSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
+ android.RegisterParallelSingletonType("cc_fuzz_presubmit_packaging", fuzzPackagingFactoryPresubmit)
}
type FuzzProperties struct {
@@ -258,25 +259,29 @@
func PackageFuzzModule(ctx android.ModuleContext, fuzzPackagedModule fuzz.FuzzPackagedModule, pctx android.PackageContext) fuzz.FuzzPackagedModule {
fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Corpus)
- builder := android.NewRuleBuilder(pctx, ctx)
intermediateDir := android.PathForModuleOut(ctx, "corpus")
+
+ // Create one rule per file to avoid MAX_ARG_STRLEN hardlimit.
for _, entry := range fuzzPackagedModule.Corpus {
- builder.Command().Text("cp").
- Input(entry).
- Output(intermediateDir.Join(ctx, entry.Base()))
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Output: intermediateDir.Join(ctx, entry.Base()),
+ Input: entry,
+ })
}
- builder.Build("copy_corpus", "copy corpus")
fuzzPackagedModule.CorpusIntermediateDir = intermediateDir
fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Data)
- builder = android.NewRuleBuilder(pctx, ctx)
intermediateDir = android.PathForModuleOut(ctx, "data")
+
+ // Create one rule per file to avoid MAX_ARG_STRLEN hardlimit.
for _, entry := range fuzzPackagedModule.Data {
- builder.Command().Text("cp").
- Input(entry).
- Output(intermediateDir.Join(ctx, entry.Rel()))
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Output: intermediateDir.Join(ctx, entry.Rel()),
+ Input: entry,
+ })
}
- builder.Build("copy_data", "copy data")
fuzzPackagedModule.DataIntermediateDir = intermediateDir
if fuzzPackagedModule.FuzzProperties.Dictionary != nil {
@@ -352,9 +357,10 @@
// their architecture & target/host specific zip file.
type ccRustFuzzPackager struct {
fuzz.FuzzPackager
- fuzzPackagingArchModules string
- fuzzTargetSharedDepsInstallPairs string
- allFuzzTargetsName string
+ fuzzPackagingArchModules string
+ fuzzTargetSharedDepsInstallPairs string
+ allFuzzTargetsName string
+ onlyIncludePresubmits bool
}
func fuzzPackagingFactory() android.Singleton {
@@ -363,6 +369,18 @@
fuzzPackagingArchModules: "SOONG_FUZZ_PACKAGING_ARCH_MODULES",
fuzzTargetSharedDepsInstallPairs: "FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
allFuzzTargetsName: "ALL_FUZZ_TARGETS",
+ onlyIncludePresubmits: false,
+ }
+ return fuzzPackager
+}
+
+func fuzzPackagingFactoryPresubmit() android.Singleton {
+
+ fuzzPackager := &ccRustFuzzPackager{
+ fuzzPackagingArchModules: "SOONG_PRESUBMIT_FUZZ_PACKAGING_ARCH_MODULES",
+ fuzzTargetSharedDepsInstallPairs: "PRESUBMIT_FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
+ allFuzzTargetsName: "ALL_PRESUBMIT_FUZZ_TARGETS",
+ onlyIncludePresubmits: true,
}
return fuzzPackager
}
@@ -386,7 +404,6 @@
if !ok || ccModule.PreventInstall() {
return
}
-
// Discard non-fuzz targets.
if ok := fuzz.IsValid(ccModule.FuzzModuleStruct()); !ok {
return
@@ -403,6 +420,9 @@
} else if ccModule.Host() {
hostOrTargetString = "host"
}
+ if s.onlyIncludePresubmits == true {
+ hostOrTargetString = "presubmit-" + hostOrTargetString
+ }
fpm := fuzz.FuzzPackagedModule{}
if ok {
@@ -427,6 +447,14 @@
// The executable.
files = append(files, fuzz.FileToZip{SourceFilePath: android.OutputFileForModule(ctx, ccModule, "unstripped")})
+ if s.onlyIncludePresubmits == true {
+ if fpm.FuzzProperties.Fuzz_config == nil {
+ return
+ }
+ if !BoolDefault(fpm.FuzzProperties.Fuzz_config.Use_for_presubmit, false){
+ return
+ }
+ }
archDirs[archOs], ok = s.BuildZipFile(ctx, module, fpm, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
if !ok {
return
diff --git a/cc/generated_cc_library.go b/cc/generated_cc_library.go
new file mode 100644
index 0000000..55e19f9
--- /dev/null
+++ b/cc/generated_cc_library.go
@@ -0,0 +1,38 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+ "android/soong/android"
+)
+
+func GeneratedCcLibraryModuleFactory(moduleName string, callbacks Generator) android.Module {
+ module, _ := NewLibrary(android.HostAndDeviceSupported)
+
+ // Can be used as both a static and a shared library.
+ module.sdkMemberTypes = []android.SdkMemberType{
+ sharedLibrarySdkMemberType,
+ staticLibrarySdkMemberType,
+ staticAndSharedLibrarySdkMemberType,
+ }
+
+ // TODO: Need to be bazelable
+ // module.bazelable = true
+ // module.bazelHandler = &ccLibraryBazelHandler{module: module}
+
+ module.generators = append(module.generators, callbacks)
+
+ return module.Init()
+}
diff --git a/cc/image.go b/cc/image.go
index e65a9aa..f91762a 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -678,10 +678,17 @@
}
}
+func squashRamdiskSrcs(m *Module) {
+ if lib, ok := m.compiler.(*libraryDecorator); ok {
+ lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs, lib.baseCompiler.Properties.Target.Ramdisk.Exclude_srcs...)
+ }
+}
+
func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
m := module.(*Module)
if variant == android.RamdiskVariation {
m.MakeAsPlatform()
+ squashRamdiskSrcs(m)
} else if variant == android.VendorRamdiskVariation {
m.MakeAsPlatform()
squashVendorRamdiskSrcs(m)
diff --git a/cc/library.go b/cc/library.go
index 3dcb5d9..df1dbc5 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -32,6 +32,20 @@
"github.com/google/blueprint/proptools"
)
+var (
+ alwaysLinkLibraries = map[string]bool{
+ // Coverage libraries are _always_ added as a whole_static_dep. By converting as these as
+ // alwayslink = True, we can add these as to deps (e.g. as a regular static dep) in Bazel
+ // without any extra complications in cc_shared_library roots to prevent linking the same
+ // library repeatedly.
+ "libprofile-extras_ndk": true,
+ "libprofile-extras": true,
+ "libprofile-clang-extras_ndk": true,
+ "libprofile-clang-extras_cfi_support": true,
+ "libprofile-clang-extras": true,
+ }
+)
+
// LibraryProperties is a collection of properties shared by cc library rules/cc.
type LibraryProperties struct {
// local file name to pass to the linker as -unexported_symbols_list
@@ -435,6 +449,10 @@
Bzl_load_location: "//build/bazel/rules/cc:cc_library_shared.bzl",
}
+ if _, ok := alwaysLinkLibraries[m.Name()]; ok {
+ staticTargetAttrs.Alwayslink = proptools.BoolPtr(true)
+ }
+
var tagsForStaticVariant bazel.StringListAttribute
if compilerAttrs.stubsSymbolFile == nil && len(compilerAttrs.stubsVersions.Value) == 0 {
tagsForStaticVariant = android.ApexAvailableTagsWithoutTestApexes(ctx, m)
@@ -2275,7 +2293,7 @@
// do not install vndk libs
// vndk libs are packaged into VNDK APEX
- if ctx.isVndk() && !ctx.IsVndkExt() {
+ if ctx.isVndk() && !ctx.IsVndkExt() && !ctx.Config().IsVndkDeprecated() {
return
}
} else if library.hasStubsVariants() && !ctx.Host() && ctx.directlyInAnyApex() {
@@ -2951,6 +2969,10 @@
var attrs interface{}
if isStatic {
commonAttrs.Deps.Add(baseAttributes.protoDependency)
+ var alwayslink *bool
+ if _, ok := alwaysLinkLibraries[module.Name()]; ok && isStatic {
+ alwayslink = proptools.BoolPtr(true)
+ }
attrs = &bazelCcLibraryStaticAttributes{
staticOrSharedAttributes: commonAttrs,
Rtti: compilerAttrs.rtti,
@@ -2964,8 +2986,10 @@
Conlyflags: compilerAttrs.conlyFlags,
Asflags: asFlags,
- Features: *features,
+ Alwayslink: alwayslink,
+ Features: *features,
}
+
} else {
commonAttrs.Dynamic_deps.Add(baseAttributes.protoDependency)
@@ -3047,7 +3071,8 @@
Conlyflags bazel.StringListAttribute
Asflags bazel.StringListAttribute
- Features bazel.StringListAttribute
+ Alwayslink *bool
+ Features bazel.StringListAttribute
}
// TODO(b/199902614): Can this be factored to share with the other Attributes?
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index f0b7cc5..9281aeb 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -31,9 +31,8 @@
func init() {
pctx.HostBinToolVariable("ndkStubGenerator", "ndkstubgen")
- pctx.HostBinToolVariable("abidiff", "abidiff")
- pctx.HostBinToolVariable("abitidy", "abitidy")
- pctx.HostBinToolVariable("abidw", "abidw")
+ pctx.HostBinToolVariable("stg", "stg")
+ pctx.HostBinToolVariable("stgdiff", "stgdiff")
}
var (
@@ -44,28 +43,20 @@
CommandDeps: []string{"$ndkStubGenerator"},
}, "arch", "apiLevel", "apiMap", "flags")
- abidw = pctx.AndroidStaticRule("abidw",
+ stg = pctx.AndroidStaticRule("stg",
blueprint.RuleParams{
- Command: "$abidw --type-id-style hash --no-corpus-path " +
- "--no-show-locs --no-comp-dir-path -w $symbolList " +
- "$in --out-file $out",
- CommandDeps: []string{"$abidw"},
+ Command: "$stg -S :$symbolList --elf $in -o $out",
+ CommandDeps: []string{"$stg"},
}, "symbolList")
- abitidy = pctx.AndroidStaticRule("abitidy",
- blueprint.RuleParams{
- Command: "$abitidy --all $flags -i $in -o $out",
- CommandDeps: []string{"$abitidy"},
- }, "flags")
-
- abidiff = pctx.AndroidStaticRule("abidiff",
+ stgdiff = pctx.AndroidStaticRule("stgdiff",
blueprint.RuleParams{
// Need to create *some* output for ninja. We don't want to use tee
// because we don't want to spam the build output with "nothing
// changed" messages, so redirect output message to $out, and if
// changes were detected print the output and fail.
- Command: "$abidiff $args $in > $out || (cat $out && false)",
- CommandDeps: []string{"$abidiff"},
+ Command: "$stgdiff $args --stg $in -o $out || (cat $out && false)",
+ CommandDeps: []string{"$stgdiff"},
}, "args")
ndkLibrarySuffix = ".ndk"
@@ -107,12 +98,6 @@
// https://github.com/android-ndk/ndk/issues/265.
Unversioned_until *string
- // If true, does not emit errors when APIs lacking type information are
- // found. This is false by default and should not be enabled outside bionic,
- // where it is enabled pending a fix for http://b/190554910 (no debug info
- // for asm implemented symbols).
- Allow_untyped_symbols *bool
-
// Headers presented by this library to the Public API Surface
Export_header_libs []string
}
@@ -326,7 +311,7 @@
apiLevel android.ApiLevel) android.OptionalPath {
subpath := filepath.Join("prebuilts/abi-dumps/ndk", apiLevel.String(),
- ctx.Arch().ArchType.String(), this.libraryName(ctx), "abi.xml")
+ ctx.Arch().ArchType.String(), this.libraryName(ctx), "abi.stg")
return android.ExistentPathForSource(ctx, subpath)
}
@@ -359,34 +344,17 @@
func (this *stubDecorator) dumpAbi(ctx ModuleContext, symbolList android.Path) {
implementationLibrary := this.findImplementationLibrary(ctx)
- abiRawPath := getNdkAbiDumpInstallBase(ctx).Join(ctx,
- this.apiLevel.String(), ctx.Arch().ArchType.String(),
- this.libraryName(ctx), "abi.raw.xml")
- ctx.Build(pctx, android.BuildParams{
- Rule: abidw,
- Description: fmt.Sprintf("abidw %s", implementationLibrary),
- Input: implementationLibrary,
- Output: abiRawPath,
- Implicit: symbolList,
- Args: map[string]string{
- "symbolList": symbolList.String(),
- },
- })
-
this.abiDumpPath = getNdkAbiDumpInstallBase(ctx).Join(ctx,
this.apiLevel.String(), ctx.Arch().ArchType.String(),
- this.libraryName(ctx), "abi.xml")
- untypedFlag := "--abort-on-untyped-symbols"
- if proptools.BoolDefault(this.properties.Allow_untyped_symbols, false) {
- untypedFlag = ""
- }
+ this.libraryName(ctx), "abi.stg")
ctx.Build(pctx, android.BuildParams{
- Rule: abitidy,
- Description: fmt.Sprintf("abitidy %s", implementationLibrary),
- Input: abiRawPath,
+ Rule: stg,
+ Description: fmt.Sprintf("stg %s", implementationLibrary),
+ Input: implementationLibrary,
+ Implicit: symbolList,
Output: this.abiDumpPath,
Args: map[string]string{
- "flags": untypedFlag,
+ "symbolList": symbolList.String(),
},
})
}
@@ -405,7 +373,7 @@
func (this *stubDecorator) diffAbi(ctx ModuleContext) {
// Catch any ABI changes compared to the checked-in definition of this API
// level.
- abiDiffPath := android.PathForModuleOut(ctx, "abidiff.timestamp")
+ abiDiffPath := android.PathForModuleOut(ctx, "stgdiff.timestamp")
prebuiltAbiDump := this.findPrebuiltAbiDump(ctx, this.apiLevel)
missingPrebuiltError := fmt.Sprintf(
"Did not find prebuilt ABI dump for %q (%q). Generate with "+
@@ -421,11 +389,14 @@
})
} else {
ctx.Build(pctx, android.BuildParams{
- Rule: abidiff,
- Description: fmt.Sprintf("abidiff %s %s", prebuiltAbiDump,
+ Rule: stgdiff,
+ Description: fmt.Sprintf("Comparing ABI %s %s", prebuiltAbiDump,
this.abiDumpPath),
Output: abiDiffPath,
Inputs: android.Paths{prebuiltAbiDump.Path(), this.abiDumpPath},
+ Args: map[string]string{
+ "args": "--format=small",
+ },
})
}
this.abiDiffPaths = append(this.abiDiffPaths, abiDiffPath)
@@ -452,13 +423,13 @@
})
} else {
ctx.Build(pctx, android.BuildParams{
- Rule: abidiff,
+ Rule: stgdiff,
Description: fmt.Sprintf("abidiff %s %s", this.abiDumpPath,
nextAbiDump),
Output: nextAbiDiffPath,
Inputs: android.Paths{this.abiDumpPath, nextAbiDump.Path()},
Args: map[string]string{
- "args": "--no-added-syms",
+ "args": "--format=small --ignore=interface_addition",
},
})
}
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index 0cf21b6..feb3880 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -58,7 +58,6 @@
func init() {
RegisterNdkModuleTypes(android.InitRegistrationContext)
- pctx.Import("android/soong/android")
}
func RegisterNdkModuleTypes(ctx android.RegistrationContext) {
diff --git a/cc/rs.go b/cc/rs.go
index 6507259..93acdc7 100644
--- a/cc/rs.go
+++ b/cc/rs.go
@@ -101,11 +101,12 @@
func rsFlags(ctx ModuleContext, flags Flags, properties *BaseCompilerProperties) Flags {
targetApi := String(properties.Renderscript.Target_api)
if targetApi == "" && ctx.useSdk() {
- switch ctx.sdkVersion() {
- case "current", "system_current", "test_current":
- // Nothing
- default:
- targetApi = android.GetNumericSdkVersion(ctx.sdkVersion())
+ targetApiLevel := android.ApiLevelOrPanic(ctx, ctx.sdkVersion())
+ if targetApiLevel.IsCurrent() || targetApiLevel.IsPreview() {
+ // If the target level is current or preview, leave the 'target-api' unset.
+ // This signals to llvm-rs-cc that the development API should be used.
+ } else {
+ targetApi = targetApiLevel.String()
}
}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 62e31d1..c1ef970 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -56,10 +56,6 @@
// higher number of "optimized out" stack variables.
// b/112437883.
"-instcombine-lower-dbg-declare=0",
- // TODO(b/159343917): HWASan and GlobalISel don't play nicely, and
- // GlobalISel is the default at -O0 on aarch64.
- "--aarch64-enable-global-isel-at-O=-1",
- "-fast-isel=false",
"-hwasan-use-after-scope=1",
"-dom-tree-reachability-max-bbs-to-explore=128",
}
@@ -646,10 +642,6 @@
if (ctx.Arch().ArchType != android.Arm64 && ctx.Arch().ArchType != android.Riscv64) || !ctx.toolchain().Bionic() {
s.Scs = nil
}
- // ...but temporarily globally disabled on riscv64 (http://b/277909695).
- if ctx.Arch().ArchType == android.Riscv64 {
- s.Scs = nil
- }
// Memtag_heap is only implemented on AArch64.
// Memtag ABI is Android specific for now, so disable for host.
diff --git a/cc/stl.go b/cc/stl.go
index f1433ef..8f92dcb 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -80,8 +80,7 @@
return ""
}
s = deduplicateStlInput(s)
- archHasNDKStl := ctx.Arch().ArchType != android.Riscv64
- if ctx.useSdk() && ctx.Device() && archHasNDKStl {
+ if ctx.useSdk() && ctx.Device() {
switch s {
case "", "system":
return "ndk_system"
@@ -120,11 +119,6 @@
}()
}
-func needsLibAndroidSupport(ctx BaseModuleContext) bool {
- version := nativeApiLevelOrPanic(ctx, ctx.sdkVersion())
- return version.LessThan(android.FirstNonLibAndroidSupportVersion)
-}
-
func staticUnwinder(ctx android.BaseModuleContext) string {
vndkVersion := ctx.Module().(*Module).VndkVersion()
@@ -184,11 +178,6 @@
} else {
deps.StaticLibs = append(deps.StaticLibs, stl.Properties.SelectedStl, "ndk_libc++abi")
}
- if needsLibAndroidSupport(ctx) {
- // Use LateStaticLibs for ndk_libandroid_support so that its include directories
- // come after ndk_libc++_static or ndk_libc++_shared.
- deps.LateStaticLibs = append(deps.LateStaticLibs, "ndk_libandroid_support")
- }
deps.StaticLibs = append(deps.StaticLibs, "ndk_libunwind")
default:
panic(fmt.Errorf("Unknown stl: %q", stl.Properties.SelectedStl))
diff --git a/cc/test.go b/cc/test.go
index 3f5f710..0be2301 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -267,7 +267,7 @@
return BoolDefault(test.LinkerProperties.Gtest, true)
}
-func (test *testDecorator) isolated(ctx BaseModuleContext) bool {
+func (test *testDecorator) isolated(ctx android.EarlyModuleContext) bool {
return BoolDefault(test.LinkerProperties.Isolated, false)
}
@@ -641,14 +641,27 @@
var _ BazelHandler = (*ccTestBazelHandler)(nil)
+// The top level target named $label is a test_suite target,
+// not the internal cc_test executable target.
+//
+// This is to ensure `b test //$label` runs the test_suite target directly,
+// which depends on tradefed_test targets, instead of the internal cc_test
+// target, which doesn't have tradefed integrations.
+//
+// However, for cquery, we want the internal cc_test executable target, which
+// has the suffix "__tf_internal".
+func mixedBuildsTestLabel(label string) string {
+ return label + "__tf_internal"
+}
+
func (handler *ccTestBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
bazelCtx := ctx.Config().BazelContext
- bazelCtx.QueueBazelRequest(label, cquery.GetCcUnstrippedInfo, android.GetConfigKey(ctx))
+ bazelCtx.QueueBazelRequest(mixedBuildsTestLabel(label), cquery.GetCcUnstrippedInfo, android.GetConfigKey(ctx))
}
func (handler *ccTestBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
bazelCtx := ctx.Config().BazelContext
- info, err := bazelCtx.GetCcUnstrippedInfo(label, android.GetConfigKey(ctx))
+ info, err := bazelCtx.GetCcUnstrippedInfo(mixedBuildsTestLabel(label), android.GetConfigKey(ctx))
if err != nil {
ctx.ModuleErrorf(err.Error())
return
@@ -669,8 +682,7 @@
type testBinaryAttributes struct {
binaryAttributes
- Gtest bool
- Isolated bool
+ Gtest *bool
tidyAttributes
tradefed.TestConfigAttributes
@@ -708,13 +720,15 @@
m.convertTidyAttributes(ctx, &testBinaryAttrs.tidyAttributes)
- for _, propIntf := range m.GetProperties() {
- if testLinkerProps, ok := propIntf.(*TestLinkerProperties); ok {
- testBinaryAttrs.Gtest = proptools.BoolDefault(testLinkerProps.Gtest, true)
- testBinaryAttrs.Isolated = proptools.BoolDefault(testLinkerProps.Isolated, true)
- break
- }
- }
+ testBinary := m.linker.(*testBinary)
+ gtest := testBinary.gtest()
+ gtestIsolated := testBinary.isolated(ctx)
+ // Use the underling bool pointer for Gtest in attrs
+ // This ensures that if this property is not set in Android.bp file, it will not be set in BUILD file either
+ // cc_test macro will default gtest to True
+ testBinaryAttrs.Gtest = testBinary.LinkerProperties.Gtest
+
+ addImplicitGtestDeps(ctx, &testBinaryAttrs, gtest, gtestIsolated)
for _, testProps := range m.GetProperties() {
if p, ok := testProps.(*TestBinaryProperties); ok {
@@ -727,7 +741,7 @@
p.Auto_gen_config,
p.Test_options.Test_suite_tag,
p.Test_config_template,
- getTradefedConfigOptions(ctx, p, testBinaryAttrs.Isolated),
+ getTradefedConfigOptions(ctx, p, gtestIsolated),
&testInstallBase,
)
testBinaryAttrs.TestConfigAttributes = testConfigAttributes
@@ -747,3 +761,28 @@
},
&testBinaryAttrs)
}
+
+// cc_test that builds using gtest needs some additional deps
+// addImplicitGtestDeps makes these deps explicit in the generated BUILD files
+func addImplicitGtestDeps(ctx android.BazelConversionPathContext, attrs *testBinaryAttributes, gtest, gtestIsolated bool) {
+ addDepsAndDedupe := func(lla *bazel.LabelListAttribute, modules []string) {
+ moduleLabels := android.BazelLabelForModuleDeps(ctx, modules)
+ lla.Value.Append(moduleLabels)
+ // Dedupe
+ lla.Value = bazel.FirstUniqueBazelLabelList(lla.Value)
+ }
+ // this must be kept in sync with Soong's implementation in:
+ // https://cs.android.com/android/_/android/platform/build/soong/+/460fb2d6d546b5ab493a7e5479998c4933a80f73:cc/test.go;l=300-313;drc=ec7314336a2b35ea30ce5438b83949c28e3ac429;bpv=1;bpt=0
+ if gtest {
+ // TODO - b/244433197: Handle canUseSdk
+ if gtestIsolated {
+ addDepsAndDedupe(&attrs.Deps, []string{"libgtest_isolated_main"})
+ addDepsAndDedupe(&attrs.Dynamic_deps, []string{"liblog"})
+ } else {
+ addDepsAndDedupe(&attrs.Deps, []string{
+ "libgtest_main",
+ "libgtest",
+ })
+ }
+ }
+}
diff --git a/cc/testing.go b/cc/testing.go
index d346739..d1632aa 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -423,11 +423,6 @@
export_include_dirs: ["ndk_libc++_shared"],
}
- ndk_prebuilt_static_stl {
- name: "ndk_libandroid_support",
- export_include_dirs: ["ndk_libandroid_support"],
- }
-
cc_library_static {
name: "libgoogle-benchmark",
sdk_version: "current",
@@ -573,16 +568,15 @@
// Additional files needed in tests that disallow non-existent source.
android.MockFS{
- "defaults/cc/common/libc.map.txt": nil,
- "defaults/cc/common/libdl.map.txt": nil,
- "defaults/cc/common/libm.map.txt": nil,
- "defaults/cc/common/ndk_libandroid_support": nil,
- "defaults/cc/common/ndk_libc++_shared": nil,
- "defaults/cc/common/crtbegin_so.c": nil,
- "defaults/cc/common/crtbegin.c": nil,
- "defaults/cc/common/crtend_so.c": nil,
- "defaults/cc/common/crtend.c": nil,
- "defaults/cc/common/crtbrand.c": nil,
+ "defaults/cc/common/libc.map.txt": nil,
+ "defaults/cc/common/libdl.map.txt": nil,
+ "defaults/cc/common/libm.map.txt": nil,
+ "defaults/cc/common/ndk_libc++_shared": nil,
+ "defaults/cc/common/crtbegin_so.c": nil,
+ "defaults/cc/common/crtbegin.c": nil,
+ "defaults/cc/common/crtend_so.c": nil,
+ "defaults/cc/common/crtend.c": nil,
+ "defaults/cc/common/crtbrand.c": nil,
"defaults/cc/common/libclang_rt.ubsan_minimal.android_arm64.a": nil,
"defaults/cc/common/libclang_rt.ubsan_minimal.android_arm.a": nil,
diff --git a/cc/util.go b/cc/util.go
index 6d8ac43..c93646b 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -28,8 +28,8 @@
return android.JoinWithPrefix(dirs.Strings(), "-I")
}
-var indexList = android.IndexList
-var inList = android.InList
+var indexList = android.IndexList[string]
+var inList = android.InList[string]
var filterList = android.FilterList
var removeListFromList = android.RemoveListFromList
var removeFromList = android.RemoveFromList
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
index e3d1179..a70a9d1 100644
--- a/cmd/merge_zips/merge_zips.go
+++ b/cmd/merge_zips/merge_zips.go
@@ -122,7 +122,7 @@
}
func (be ZipEntryFromBuffer) WriteToZip(dest string, zw *zip.Writer) error {
- w, err := zw.CreateHeader(be.fh)
+ w, err := zw.CreateHeaderAndroid(be.fh)
if err != nil {
return err
}
@@ -562,6 +562,8 @@
}
}
+ var jarServices jar.Services
+
// Finally, add entries from all the input zips.
for _, inputZip := range inputZips {
_, copyFully := zipsToNotStrip[inputZip.Name()]
@@ -570,6 +572,14 @@
}
for i, entry := range inputZip.Entries() {
+ if emulateJar && jarServices.IsServiceFile(entry) {
+ // If this is a jar, collect service files to combine instead of adding them to the zip.
+ err := jarServices.AddServiceFile(entry)
+ if err != nil {
+ return err
+ }
+ continue
+ }
if copyFully || !out.isEntryExcluded(entry.Name) {
if err := out.copyEntry(inputZip, i); err != nil {
return err
@@ -585,6 +595,16 @@
}
if emulateJar {
+ // Combine all the service files into a single list of combined service files and add them to the zip.
+ for _, serviceFile := range jarServices.ServiceFiles() {
+ _, err := out.addZipEntry(serviceFile.Name, ZipEntryFromBuffer{
+ fh: serviceFile.FileHeader,
+ content: serviceFile.Contents,
+ })
+ if err != nil {
+ return err
+ }
+ }
return out.writeEntries(out.jarSorted())
} else if sortEntries {
return out.writeEntries(out.alphanumericSorted())
diff --git a/cmd/merge_zips/merge_zips_test.go b/cmd/merge_zips/merge_zips_test.go
index cb58436..767d4e61 100644
--- a/cmd/merge_zips/merge_zips_test.go
+++ b/cmd/merge_zips/merge_zips_test.go
@@ -17,6 +17,7 @@
import (
"bytes"
"fmt"
+ "hash/crc32"
"os"
"strconv"
"strings"
@@ -27,28 +28,34 @@
)
type testZipEntry struct {
- name string
- mode os.FileMode
- data []byte
+ name string
+ mode os.FileMode
+ data []byte
+ method uint16
}
var (
- A = testZipEntry{"A", 0755, []byte("foo")}
- a = testZipEntry{"a", 0755, []byte("foo")}
- a2 = testZipEntry{"a", 0755, []byte("FOO2")}
- a3 = testZipEntry{"a", 0755, []byte("Foo3")}
- bDir = testZipEntry{"b/", os.ModeDir | 0755, nil}
- bbDir = testZipEntry{"b/b/", os.ModeDir | 0755, nil}
- bbb = testZipEntry{"b/b/b", 0755, nil}
- ba = testZipEntry{"b/a", 0755, []byte("foob")}
- bc = testZipEntry{"b/c", 0755, []byte("bar")}
- bd = testZipEntry{"b/d", 0700, []byte("baz")}
- be = testZipEntry{"b/e", 0700, []byte("")}
+ A = testZipEntry{"A", 0755, []byte("foo"), zip.Deflate}
+ a = testZipEntry{"a", 0755, []byte("foo"), zip.Deflate}
+ a2 = testZipEntry{"a", 0755, []byte("FOO2"), zip.Deflate}
+ a3 = testZipEntry{"a", 0755, []byte("Foo3"), zip.Deflate}
+ bDir = testZipEntry{"b/", os.ModeDir | 0755, nil, zip.Deflate}
+ bbDir = testZipEntry{"b/b/", os.ModeDir | 0755, nil, zip.Deflate}
+ bbb = testZipEntry{"b/b/b", 0755, nil, zip.Deflate}
+ ba = testZipEntry{"b/a", 0755, []byte("foo"), zip.Deflate}
+ bc = testZipEntry{"b/c", 0755, []byte("bar"), zip.Deflate}
+ bd = testZipEntry{"b/d", 0700, []byte("baz"), zip.Deflate}
+ be = testZipEntry{"b/e", 0700, []byte(""), zip.Deflate}
- metainfDir = testZipEntry{jar.MetaDir, os.ModeDir | 0755, nil}
- manifestFile = testZipEntry{jar.ManifestFile, 0755, []byte("manifest")}
- manifestFile2 = testZipEntry{jar.ManifestFile, 0755, []byte("manifest2")}
- moduleInfoFile = testZipEntry{jar.ModuleInfoClass, 0755, []byte("module-info")}
+ service1a = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\n"), zip.Store}
+ service1b = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass3\n"), zip.Deflate}
+ service1combined = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\nclass3\n"), zip.Store}
+ service2 = testZipEntry{"META-INF/services/service2", 0755, []byte("class1\nclass2\n"), zip.Deflate}
+
+ metainfDir = testZipEntry{jar.MetaDir, os.ModeDir | 0755, nil, zip.Deflate}
+ manifestFile = testZipEntry{jar.ManifestFile, 0755, []byte("manifest"), zip.Deflate}
+ manifestFile2 = testZipEntry{jar.ManifestFile, 0755, []byte("manifest2"), zip.Deflate}
+ moduleInfoFile = testZipEntry{jar.ModuleInfoClass, 0755, []byte("module-info"), zip.Deflate}
)
type testInputZip struct {
@@ -236,6 +243,15 @@
"in1": true,
},
},
+ {
+ name: "services",
+ in: [][]testZipEntry{
+ {service1a, service2},
+ {service1b},
+ },
+ jar: true,
+ out: []testZipEntry{service1combined, service2},
+ },
}
for _, test := range testCases {
@@ -256,7 +272,7 @@
closeErr := writer.Close()
if closeErr != nil {
- t.Fatal(err)
+ t.Fatal(closeErr)
}
if test.err != "" {
@@ -266,12 +282,16 @@
t.Fatal("incorrect err, want:", test.err, "got:", err)
}
return
+ } else if err != nil {
+ t.Fatal("unexpected err: ", err)
}
if !bytes.Equal(want, out.Bytes()) {
t.Error("incorrect zip output")
t.Errorf("want:\n%s", dumpZip(want))
t.Errorf("got:\n%s", dumpZip(out.Bytes()))
+ os.WriteFile("/tmp/got.zip", out.Bytes(), 0755)
+ os.WriteFile("/tmp/want.zip", want, 0755)
}
})
}
@@ -286,8 +306,14 @@
Name: e.name,
}
fh.SetMode(e.mode)
+ fh.Method = e.method
+ fh.UncompressedSize64 = uint64(len(e.data))
+ fh.CRC32 = crc32.ChecksumIEEE(e.data)
+ if fh.Method == zip.Store {
+ fh.CompressedSize64 = fh.UncompressedSize64
+ }
- w, err := zw.CreateHeader(&fh)
+ w, err := zw.CreateHeaderAndroid(&fh)
if err != nil {
panic(err)
}
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 22d64a2..62b3333 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -121,6 +121,10 @@
defer ctx.EventHandler.End("mixed_build")
bazelHook := func() error {
+ err := ctx.Config().BazelContext.QueueBazelSandwichCqueryRequests(ctx.Config())
+ if err != nil {
+ return err
+ }
return ctx.Config().BazelContext.InvokeBazel(ctx.Config(), ctx)
}
ctx.SetBeforePrepareBuildActionsHook(bazelHook)
@@ -225,7 +229,7 @@
ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
// Create soong_injection repository
- soongInjectionFiles, err := bp2build.CreateSoongInjectionDirFiles(codegenContext, bp2build.CreateCodegenMetrics())
+ soongInjectionFiles, workspaceFiles, err := bp2build.CreateSoongInjectionDirFiles(codegenContext, bp2build.CreateCodegenMetrics())
maybeQuit(err, "")
absoluteSoongInjectionDir := shared.JoinPath(topDir, ctx.Config().SoongOutDir(), bazel.SoongInjectionDirName)
for _, file := range soongInjectionFiles {
@@ -236,6 +240,9 @@
// to allow users to edit/experiment in the synthetic workspace.
writeReadWriteFile(absoluteSoongInjectionDir, file)
}
+ for _, file := range workspaceFiles {
+ writeReadWriteFile(absoluteApiBp2buildDir, file)
+ }
workspace := shared.JoinPath(ctx.Config().SoongOutDir(), "api_bp2build")
// Create the symlink forest
diff --git a/cmd/zip2zip/BUILD.bazel b/cmd/zip2zip/BUILD.bazel
deleted file mode 100644
index 1915a2d..0000000
--- a/cmd/zip2zip/BUILD.bazel
+++ /dev/null
@@ -1,18 +0,0 @@
-# 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.
-
-alias(
- name = "zip2zip",
- actual = "//prebuilts/build-tools:linux-x86/bin/zip2zip",
-)
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index ada4712..94b795f 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -371,6 +371,8 @@
// Specifies whether fuzz target should check presubmitted code changes for crashes.
// Defaults to false.
Use_for_presubmit *bool `json:"use_for_presubmit,omitempty"`
+ // Specify which paths to exclude from fuzzing coverage reports
+ Exclude_paths_from_reports []string `json:"exclude_paths_from_reports,omitempty"`
}
type FuzzFrameworks struct {
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
index c6fa030..afa52cc 100644
--- a/genrule/allowlists.go
+++ b/genrule/allowlists.go
@@ -116,6 +116,25 @@
"aidl_camera_build_version",
"cronet_aml_base_android_runtime_unchecked_jni_headers",
"cronet_aml_base_android_runtime_jni_headers",
+ "aidl-golden-test-build-hook-gen",
+ "PacketStreamerStub_h",
+ "FrontendStub_cc",
+ "FrontendStub_h",
+ "PacketStreamerStub_cc",
+ "pixelstatsatoms.h",
+ "pixelatoms_defs.h",
+ "pixelstatsatoms.cpp",
+ "hidl_java_impl_test_gen",
+ "cronet_aml_base_android_runtime_jni_headers__testing",
+ "cronet_aml_base_android_runtime_unchecked_jni_headers__testing",
+ "hidl_cpp_impl_test_gen-sources",
+ "fdt_test_tree_multiple_memory_ranges_dtb",
+ "fdt_test_tree_one_memory_range_dtb",
+ "fdt_test_tree_empty_memory_range_dtb",
+ "ltp_config_arm_64_lowmem",
+ "ltp_config_arm_64_lowmem_hwasan",
+ "ltp_config_x86",
+ "libbssl_sys_src_nostd",
}
SandboxingDenyPathList = []string{
diff --git a/genrule/genrule.go b/genrule/genrule.go
index a470c5e..69ba1e9 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -296,6 +296,9 @@
for _, dir := range g.properties.Export_include_dirs {
g.exportedIncludeDirs = append(g.exportedIncludeDirs,
android.PathForModuleGen(ctx, g.subDir, ctx.ModuleDir(), dir))
+ // Also export without ModuleDir for consistency with Export_include_dirs not being set
+ g.exportedIncludeDirs = append(g.exportedIncludeDirs,
+ android.PathForModuleGen(ctx, g.subDir, dir))
}
} else {
g.exportedIncludeDirs = append(g.exportedIncludeDirs, android.PathForModuleGen(ctx, g.subDir))
@@ -991,6 +994,7 @@
tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
+ bazelName := m.Name()
if ctx.ModuleType() == "gensrcs" {
props := bazel.BazelTargetModuleProperties{
Rule_class: "gensrcs",
@@ -1018,7 +1022,6 @@
break
}
}
- bazelName := m.Name()
for _, out := range outs {
if out == bazelName {
// This is a workaround to circumvent a Bazel warning where a genrule's
@@ -1043,6 +1046,54 @@
Tags: tags,
}, attrs)
}
+
+ if m.needsCcLibraryHeadersBp2build() {
+ includeDirs := make([]string, len(m.properties.Export_include_dirs)*2)
+ for i, dir := range m.properties.Export_include_dirs {
+ includeDirs[i*2] = dir
+ includeDirs[i*2+1] = filepath.Clean(filepath.Join(ctx.ModuleDir(), dir))
+ }
+ attrs := &ccHeaderLibraryAttrs{
+ Hdrs: []string{":" + bazelName},
+ Export_includes: includeDirs,
+ }
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "cc_library_headers",
+ Bzl_load_location: "//build/bazel/rules/cc:cc_library_headers.bzl",
+ }
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{
+ Name: m.Name() + genruleHeaderLibrarySuffix,
+ Tags: tags,
+ }, attrs)
+
+ }
+}
+
+const genruleHeaderLibrarySuffix = "__header_library"
+
+func (m *Module) needsCcLibraryHeadersBp2build() bool {
+ return len(m.properties.Export_include_dirs) > 0
+}
+
+// GenruleCcHeaderMapper is a bazel.LabelMapper function to map genrules to a cc_library_headers
+// target when they export multiple include directories.
+func GenruleCcHeaderLabelMapper(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
+ mod, exists := ctx.ModuleFromName(label.OriginalModuleName)
+ if !exists {
+ return label.Label, false
+ }
+ if m, ok := mod.(*Module); ok {
+ if m.needsCcLibraryHeadersBp2build() {
+ return label.Label + genruleHeaderLibrarySuffix, true
+ }
+ }
+ return label.Label, false
+}
+
+type ccHeaderLibraryAttrs struct {
+ Hdrs []string
+
+ Export_includes []string
}
var Bool = proptools.Bool
@@ -1096,6 +1147,7 @@
}
}).(*sandboxingAllowlistSets)
}
+
func getSandboxedRuleBuilder(ctx android.ModuleContext, r *android.RuleBuilder) *android.RuleBuilder {
if !ctx.DeviceConfig().GenruleSandboxing() {
return r.SandboxTools()
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 6301bbf..7c14531 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -845,6 +845,49 @@
result.ModuleForTests("gen_all", "").Module().(*useSource).srcs)
}
+func TestGenruleInterface(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForGenRuleTest,
+ android.FixtureMergeMockFs(android.MockFS{
+ "package-dir/Android.bp": []byte(`
+ genrule {
+ name: "module-name",
+ cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)",
+ srcs: [
+ "src/foo.proto",
+ ],
+ out: ["proto.h", "bar/proto.h"],
+ export_include_dirs: [".", "bar"],
+ }
+ `),
+ }),
+ ).RunTest(t)
+
+ exportedIncludeDirs := []string{
+ "out/soong/.intermediates/package-dir/module-name/gen/package-dir",
+ "out/soong/.intermediates/package-dir/module-name/gen",
+ "out/soong/.intermediates/package-dir/module-name/gen/package-dir/bar",
+ "out/soong/.intermediates/package-dir/module-name/gen/bar",
+ }
+ gen := result.Module("module-name", "").(*Module)
+
+ android.AssertPathsRelativeToTopEquals(
+ t,
+ "include path",
+ exportedIncludeDirs,
+ gen.GeneratedHeaderDirs(),
+ )
+ android.AssertPathsRelativeToTopEquals(
+ t,
+ "files",
+ []string{
+ "out/soong/.intermediates/package-dir/module-name/gen/proto.h",
+ "out/soong/.intermediates/package-dir/module-name/gen/bar/proto.h",
+ },
+ gen.GeneratedSourceFiles(),
+ )
+}
+
func TestGenSrcsWithNonRootAndroidBpOutputFiles(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForGenRuleTest,
diff --git a/jar/Android.bp b/jar/Android.bp
index 46113d8..c03e491 100644
--- a/jar/Android.bp
+++ b/jar/Android.bp
@@ -21,6 +21,7 @@
pkgPath: "android/soong/jar",
srcs: [
"jar.go",
+ "services.go",
],
testSrcs: [
"jar_test.go",
diff --git a/jar/services.go b/jar/services.go
new file mode 100644
index 0000000..d06a6dc
--- /dev/null
+++ b/jar/services.go
@@ -0,0 +1,128 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jar
+
+import (
+ "android/soong/third_party/zip"
+ "bufio"
+ "hash/crc32"
+ "sort"
+ "strings"
+)
+
+const servicesPrefix = "META-INF/services/"
+
+// Services is used to collect service files from multiple zip files and produce a list of ServiceFiles containing
+// the unique lines from all the input zip entries with the same name.
+type Services struct {
+ services map[string]*ServiceFile
+}
+
+// ServiceFile contains the combined contents of all input zip entries with a single name.
+type ServiceFile struct {
+ Name string
+ FileHeader *zip.FileHeader
+ Contents []byte
+ Lines []string
+}
+
+// IsServiceFile returns true if the zip entry is in the META-INF/services/ directory.
+func (Services) IsServiceFile(entry *zip.File) bool {
+ return strings.HasPrefix(entry.Name, servicesPrefix)
+}
+
+// AddServiceFile adds a zip entry in the META-INF/services/ directory to the list of service files that need
+// to be combined.
+func (j *Services) AddServiceFile(entry *zip.File) error {
+ if j.services == nil {
+ j.services = map[string]*ServiceFile{}
+ }
+
+ service := entry.Name
+ serviceFile := j.services[service]
+ fh := entry.FileHeader
+ if serviceFile == nil {
+ serviceFile = &ServiceFile{
+ Name: service,
+ FileHeader: &fh,
+ }
+ j.services[service] = serviceFile
+ }
+
+ f, err := entry.Open()
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() {
+ line := scanner.Text()
+ if line != "" {
+ serviceFile.Lines = append(serviceFile.Lines, line)
+ }
+ }
+
+ if err := scanner.Err(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// ServiceFiles returns the list of combined service files, each containing all the unique lines from the
+// corresponding service files in the input zip entries.
+func (j *Services) ServiceFiles() []ServiceFile {
+ services := make([]ServiceFile, 0, len(j.services))
+
+ for _, serviceFile := range j.services {
+ serviceFile.Lines = dedupServicesLines(serviceFile.Lines)
+ serviceFile.Lines = append(serviceFile.Lines, "")
+ serviceFile.Contents = []byte(strings.Join(serviceFile.Lines, "\n"))
+
+ serviceFile.FileHeader.UncompressedSize64 = uint64(len(serviceFile.Contents))
+ serviceFile.FileHeader.CRC32 = crc32.ChecksumIEEE(serviceFile.Contents)
+ if serviceFile.FileHeader.Method == zip.Store {
+ serviceFile.FileHeader.CompressedSize64 = serviceFile.FileHeader.UncompressedSize64
+ }
+
+ services = append(services, *serviceFile)
+ }
+
+ sort.Slice(services, func(i, j int) bool {
+ return services[i].Name < services[j].Name
+ })
+
+ return services
+}
+
+func dedupServicesLines(in []string) []string {
+ writeIndex := 0
+outer:
+ for readIndex := 0; readIndex < len(in); readIndex++ {
+ for compareIndex := 0; compareIndex < writeIndex; compareIndex++ {
+ if interface{}(in[readIndex]) == interface{}(in[compareIndex]) {
+ // The value at readIndex already exists somewhere in the output region
+ // of the slice before writeIndex, skip it.
+ continue outer
+ }
+ }
+ if readIndex != writeIndex {
+ in[writeIndex] = in[readIndex]
+ }
+ writeIndex++
+ }
+ return in[0:writeIndex]
+}
diff --git a/java/aar.go b/java/aar.go
index 01bd103..180e1d7 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -88,28 +88,40 @@
// do not include AndroidManifest from dependent libraries
Dont_merge_manifests *bool
+ // If use_resource_processor is set, use Bazel's resource processor instead of aapt2 to generate R.class files.
+ // The resource processor produces more optimal R.class files that only list resources in the package of the
+ // library that provided them, as opposed to aapt2 which produces R.java files for every package containing
+ // every resource. Using the resource processor can provide significant build time speedups, but requires
+ // fixing the module to use the correct package to reference each resource, and to avoid having any other
+ // libraries in the tree that use the same package name. Defaults to false, but will default to true in the
+ // future.
+ Use_resource_processor *bool
+
// true if RRO is enforced for any of the dependent modules
RROEnforcedForDependent bool `blueprint:"mutated"`
}
type aapt struct {
- aaptSrcJar android.Path
- exportPackage android.Path
- manifestPath android.Path
- proguardOptionsFile android.Path
- rTxt android.Path
- extraAaptPackagesFile android.Path
- mergedManifestFile android.Path
- noticeFile android.OptionalPath
- assetPackage android.OptionalPath
- isLibrary bool
- defaultManifestVersion string
- useEmbeddedNativeLibs bool
- useEmbeddedDex bool
- usesNonSdkApis bool
- hasNoCode bool
- LoggingParent string
- resourceFiles android.Paths
+ aaptSrcJar android.Path
+ transitiveAaptRJars android.Paths
+ transitiveAaptResourcePackages android.Paths
+ exportPackage android.Path
+ manifestPath android.Path
+ proguardOptionsFile android.Path
+ rTxt android.Path
+ rJar android.Path
+ extraAaptPackagesFile android.Path
+ mergedManifestFile android.Path
+ noticeFile android.OptionalPath
+ assetPackage android.OptionalPath
+ isLibrary bool
+ defaultManifestVersion string
+ useEmbeddedNativeLibs bool
+ useEmbeddedDex bool
+ usesNonSdkApis bool
+ hasNoCode bool
+ LoggingParent string
+ resourceFiles android.Paths
splitNames []string
splits []split
@@ -139,6 +151,10 @@
}
}
+func (a *aapt) useResourceProcessorBusyBox() bool {
+ return BoolDefault(a.aaptProperties.Use_resource_processor, false)
+}
+
func (a *aapt) ExportPackage() android.Path {
return a.exportPackage
}
@@ -175,8 +191,6 @@
// Flags specified in Android.bp
linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...)
- linkFlags = append(linkFlags, "--no-static-lib-packages")
-
// Find implicit or explicit asset and resource dirs
assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets")
resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res")
@@ -348,6 +362,19 @@
linkFlags = append(linkFlags, "--static-lib")
}
+ if a.isLibrary && a.useResourceProcessorBusyBox() {
+ // When building an android_library using ResourceProcessorBusyBox the resources are merged into
+ // package-res.apk with --merge-only, but --no-static-lib-packages is not used so that R.txt only
+ // contains resources from this library.
+ linkFlags = append(linkFlags, "--merge-only")
+ } else {
+ // When building and app or when building an android_library without ResourceProcessorBusyBox
+ // --no-static-lib-packages is used to put all the resources into the app. If ResourceProcessorBusyBox
+ // is used then the app's R.txt will be post-processed along with the R.txt files from dependencies to
+ // sort resources into the right packages in R.class.
+ linkFlags = append(linkFlags, "--no-static-lib-packages")
+ }
+
packageRes := android.PathForModuleOut(ctx, "package-res.apk")
// the subdir "android" is required to be filtered by package names
srcJar := android.PathForModuleGen(ctx, "android", "R.srcjar")
@@ -355,6 +382,7 @@
rTxt := android.PathForModuleOut(ctx, "R.txt")
// This file isn't used by Soong, but is generated for exporting
extraPackages := android.PathForModuleOut(ctx, "extra_packages")
+ var transitiveRJars android.Paths
var compiledResDirs []android.Paths
for _, dir := range resDirs {
@@ -374,7 +402,23 @@
// of transitiveStaticLibs.
transitiveStaticLibs := android.ReversePaths(staticDeps.resPackages())
- compiledOverlay = append(compiledOverlay, transitiveStaticLibs...)
+ if a.isLibrary && a.useResourceProcessorBusyBox() {
+ // When building an android_library with ResourceProcessorBusyBox enabled treat static library dependencies
+ // as imports. The resources from dependencies will not be merged into this module's package-res.apk, and
+ // instead modules depending on this module will reference package-res.apk from all transitive static
+ // dependencies.
+ for _, staticDep := range staticDeps {
+ linkDeps = append(linkDeps, staticDep.resPackage)
+ linkFlags = append(linkFlags, "-I "+staticDep.resPackage.String())
+ if staticDep.usedResourceProcessor {
+ transitiveRJars = append(transitiveRJars, staticDep.rJar)
+ }
+ }
+ } else {
+ // When building an app or building a library without ResourceProcessorBusyBox enabled all static
+ // dependencies are compiled into this module's package-res.apk as overlays.
+ compiledOverlay = append(compiledOverlay, transitiveStaticLibs...)
+ }
if len(transitiveStaticLibs) > 0 {
// If we are using static android libraries, every source file becomes an overlay.
@@ -437,7 +481,16 @@
a.assetPackage = android.OptionalPathForPath(assets)
}
+ if a.useResourceProcessorBusyBox() {
+ rJar := android.PathForModuleOut(ctx, "busybox/R.jar")
+ resourceProcessorBusyBoxGenerateBinaryR(ctx, rTxt, a.mergedManifestFile, rJar, staticDeps, a.isLibrary)
+ transitiveRJars = append(transitiveRJars, rJar)
+ a.rJar = rJar
+ }
+
a.aaptSrcJar = srcJar
+ a.transitiveAaptRJars = transitiveRJars
+ a.transitiveAaptResourcePackages = staticDeps.resPackages()
a.exportPackage = packageRes
a.manifestPath = manifestPath
a.proguardOptionsFile = proguardOptionsFile
@@ -449,7 +502,11 @@
resPackage: a.exportPackage,
manifest: a.manifestPath,
additionalManifests: additionalManifests,
+ rTxt: a.rTxt,
+ rJar: a.rJar,
assets: a.assetPackage,
+
+ usedResourceProcessor: a.useResourceProcessorBusyBox(),
}).
Transitive(staticResourcesNodesDepSet).Build()
a.rroDirsDepSet = android.NewDepSetBuilder[rroDir](android.TOPOLOGICAL).
@@ -461,34 +518,93 @@
Transitive(staticManifestsDepSet).Build()
}
+var resourceProcessorBusyBox = pctx.AndroidStaticRule("resourceProcessorBusyBox",
+ blueprint.RuleParams{
+ Command: "${config.JavaCmd} -cp ${config.ResourceProcessorBusyBox} " +
+ "com.google.devtools.build.android.ResourceProcessorBusyBox --tool=GENERATE_BINARY_R -- @${out}.args && " +
+ "if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out}; fi",
+ CommandDeps: []string{"${config.ResourceProcessorBusyBox}"},
+ Rspfile: "${out}.args",
+ RspfileContent: "--primaryRTxt ${rTxt} --primaryManifest ${manifest} --classJarOutput ${out}.tmp ${args}",
+ Restat: true,
+ }, "rTxt", "manifest", "args")
+
+// resourceProcessorBusyBoxGenerateBinaryR converts the R.txt file produced by aapt2 into R.class files
+// using Bazel's ResourceProcessorBusyBox tool, which is faster than compiling the R.java files and
+// supports producing classes for static dependencies that only include resources from that dependency.
+func resourceProcessorBusyBoxGenerateBinaryR(ctx android.ModuleContext, rTxt, manifest android.Path,
+ rJar android.WritablePath, transitiveDeps transitiveAarDeps, isLibrary bool) {
+
+ var args []string
+ var deps android.Paths
+
+ if !isLibrary {
+ // When compiling an app, pass all R.txt and AndroidManifest.xml from transitive static library dependencies
+ // to ResourceProcessorBusyBox so that it can regenerate R.class files with the final resource IDs for each
+ // package.
+ args, deps = transitiveDeps.resourceProcessorDeps()
+ } else {
+ // When compiling a library don't pass any dependencies as it only needs to generate an R.class file for this
+ // library. Pass --finalFields=false so that the R.class file contains non-final fields so they don't get
+ // inlined into the library before the final IDs are assigned during app compilation.
+ args = append(args, "--finalFields=false")
+ }
+
+ deps = append(deps, rTxt, manifest)
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: resourceProcessorBusyBox,
+ Output: rJar,
+ Implicits: deps,
+ Description: "ResourceProcessorBusyBox",
+ Args: map[string]string{
+ "rTxt": rTxt.String(),
+ "manifest": manifest.String(),
+ "args": strings.Join(args, " "),
+ },
+ })
+}
+
type resourcesNode struct {
resPackage android.Path
manifest android.Path
additionalManifests android.Paths
+ rTxt android.Path
+ rJar android.Path
assets android.OptionalPath
+
+ usedResourceProcessor bool
}
type transitiveAarDeps []*resourcesNode
func (t transitiveAarDeps) resPackages() android.Paths {
- var paths android.Paths
+ paths := make(android.Paths, 0, len(t))
for _, dep := range t {
paths = append(paths, dep.resPackage)
}
- return android.FirstUniquePaths(paths)
+ return paths
}
func (t transitiveAarDeps) manifests() android.Paths {
- var paths android.Paths
+ paths := make(android.Paths, 0, len(t))
for _, dep := range t {
paths = append(paths, dep.manifest)
paths = append(paths, dep.additionalManifests...)
}
- return android.FirstUniquePaths(paths)
+ return paths
+}
+
+func (t transitiveAarDeps) resourceProcessorDeps() (args []string, deps android.Paths) {
+ for _, dep := range t {
+ args = append(args, "--library="+dep.rTxt.String()+","+dep.manifest.String())
+ deps = append(deps, dep.rTxt, dep.manifest)
+ }
+ return args, deps
}
func (t transitiveAarDeps) assets() android.Paths {
- var paths android.Paths
+ paths := make(android.Paths, 0, len(t))
for _, dep := range t {
if dep.assets.Valid() {
paths = append(paths, dep.assets.Path())
@@ -611,9 +727,14 @@
a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
- ctx.CheckbuildFile(a.proguardOptionsFile)
- ctx.CheckbuildFile(a.exportPackage)
- ctx.CheckbuildFile(a.aaptSrcJar)
+ a.stem = proptools.StringDefault(a.overridableDeviceProperties.Stem, ctx.ModuleName())
+
+ ctx.CheckbuildFile(a.aapt.proguardOptionsFile)
+ ctx.CheckbuildFile(a.aapt.exportPackage)
+ ctx.CheckbuildFile(a.aapt.aaptSrcJar)
+ if a.useResourceProcessorBusyBox() {
+ ctx.CheckbuildFile(a.aapt.rJar)
+ }
// apps manifests are handled by aapt, don't let Module see them
a.properties.Manifest = nil
@@ -625,7 +746,22 @@
a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles,
a.proguardOptionsFile)
- a.Module.compile(ctx, a.aaptSrcJar)
+ var extraSrcJars android.Paths
+ var extraCombinedJars android.Paths
+ var extraClasspathJars android.Paths
+ if a.useResourceProcessorBusyBox() {
+ // When building a library with ResourceProcessorBusyBox enabled ResourceProcessorBusyBox for this
+ // library and each of the transitive static android_library dependencies has already created an
+ // R.class file for the appropriate package. Add all of those R.class files to the classpath.
+ extraClasspathJars = a.transitiveAaptRJars
+ } else {
+ // When building a library without ResourceProcessorBusyBox the aapt2 rule creates R.srcjar containing
+ // R.java files for the library's package and the packages from all transitive static android_library
+ // dependencies. Compile the srcjar alongside the rest of the sources.
+ extraSrcJars = android.Paths{a.aapt.aaptSrcJar}
+ }
+
+ a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
a.aarFile = android.PathForModuleOut(ctx, ctx.ModuleName()+".aar")
var res android.Paths
@@ -727,12 +863,15 @@
properties AARImportProperties
- classpathFile android.WritablePath
- proguardFlags android.WritablePath
- exportPackage android.WritablePath
- extraAaptPackagesFile android.WritablePath
- manifest android.WritablePath
- assetsPackage android.WritablePath
+ classpathFile android.WritablePath
+ proguardFlags android.WritablePath
+ exportPackage android.WritablePath
+ transitiveAaptResourcePackages android.Paths
+ extraAaptPackagesFile android.WritablePath
+ manifest android.WritablePath
+ assetsPackage android.WritablePath
+ rTxt android.WritablePath
+ rJar android.WritablePath
resourcesNodesDepSet *android.DepSet[*resourcesNode]
manifestsDepSet *android.DepSet[android.Path]
@@ -901,12 +1040,13 @@
a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar")
a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml")
+ aarRTxt := extractedAARDir.Join(ctx, "R.txt")
a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip")
ctx.Build(pctx, android.BuildParams{
Rule: unzipAAR,
Input: a.aarPath,
- Outputs: android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage},
+ Outputs: android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage, aarRTxt},
Description: "unzip AAR",
Args: map[string]string{
"outDir": extractedAARDir.String(),
@@ -926,14 +1066,14 @@
// the subdir "android" is required to be filtered by package names
srcJar := android.PathForModuleGen(ctx, "android", "R.srcjar")
proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
- rTxt := android.PathForModuleOut(ctx, "R.txt")
+ a.rTxt = android.PathForModuleOut(ctx, "R.txt")
a.extraAaptPackagesFile = android.PathForModuleOut(ctx, "extra_packages")
var linkDeps android.Paths
linkFlags := []string{
"--static-lib",
- "--no-static-lib-packages",
+ "--merge-only",
"--auto-add-overlay",
}
@@ -946,25 +1086,35 @@
_ = staticRRODirsDepSet
staticDeps := transitiveAarDeps(staticResourcesNodesDepSet.ToList())
- // AAPT2 overlays are in lowest to highest priority order, reverse the topological order
- // of transitiveStaticLibs.
- transitiveStaticLibs := android.ReversePaths(staticDeps.resPackages())
-
linkDeps = append(linkDeps, sharedLibs...)
- linkDeps = append(linkDeps, transitiveStaticLibs...)
+ linkDeps = append(linkDeps, staticDeps.resPackages()...)
linkFlags = append(linkFlags, libFlags...)
- overlayRes := append(android.Paths{flata}, transitiveStaticLibs...)
+ overlayRes := android.Paths{flata}
+
+ // Treat static library dependencies of static libraries as imports.
+ transitiveStaticLibs := staticDeps.resPackages()
+ linkDeps = append(linkDeps, transitiveStaticLibs...)
+ for _, staticLib := range transitiveStaticLibs {
+ linkFlags = append(linkFlags, "-I "+staticLib.String())
+ }
transitiveAssets := android.ReverseSliceInPlace(staticDeps.assets())
- aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile,
+ aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, a.rTxt, a.extraAaptPackagesFile,
linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil)
+ a.rJar = android.PathForModuleOut(ctx, "busybox/R.jar")
+ resourceProcessorBusyBoxGenerateBinaryR(ctx, a.rTxt, a.manifest, a.rJar, nil, true)
+
resourcesNodesDepSetBuilder := android.NewDepSetBuilder[*resourcesNode](android.TOPOLOGICAL)
resourcesNodesDepSetBuilder.Direct(&resourcesNode{
resPackage: a.exportPackage,
manifest: a.manifest,
+ rTxt: a.rTxt,
+ rJar: a.rJar,
assets: android.OptionalPathForPath(a.assetsPackage),
+
+ usedResourceProcessor: true,
})
resourcesNodesDepSetBuilder.Transitive(staticResourcesNodesDepSet)
a.resourcesNodesDepSet = resourcesNodesDepSetBuilder.Build()
@@ -979,6 +1129,8 @@
_ = staticManifestsDepSet
a.manifestsDepSet = manifestDepSetBuilder.Build()
+ a.transitiveAaptResourcePackages = staticDeps.resPackages()
+
a.collectTransitiveHeaderJars(ctx)
ctx.SetProvider(JavaInfoProvider, JavaInfo{
HeaderJars: android.PathsIfNonNil(a.classpathFile),
@@ -986,6 +1138,7 @@
TransitiveStaticLibsHeaderJars: a.transitiveStaticLibsHeaderJars,
ImplementationAndResourcesJars: android.PathsIfNonNil(a.classpathFile),
ImplementationJars: android.PathsIfNonNil(a.classpathFile),
+ // TransitiveAconfigFiles: // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
})
if proptools.Bool(a.properties.Extract_jni) {
diff --git a/java/androidmk.go b/java/androidmk.go
index 13cc96a..82505e9 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -123,6 +123,8 @@
if library.dexpreopter.configPath != nil {
entries.SetPath("LOCAL_SOONG_DEXPREOPT_CONFIG", library.dexpreopter.configPath)
}
+
+ entries.SetOptionalPaths("LOCAL_ACONFIG_FILES", library.getTransitiveAconfigFiles().ToList())
},
},
})
@@ -220,6 +222,7 @@
entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile)
entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion.String())
entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem())
+ // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
},
},
}}
@@ -244,6 +247,7 @@
entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", prebuilt.dexpreopter.builtInstalled)
}
entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem())
+ // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
},
},
}}
@@ -265,10 +269,12 @@
entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.classpathFile)
entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.classpathFile)
entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", prebuilt.exportPackage)
+ entries.SetPaths("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", prebuilt.transitiveAaptResourcePackages)
entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", prebuilt.proguardFlags)
entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", prebuilt.extraAaptPackagesFile)
entries.SetPath("LOCAL_FULL_MANIFEST_FILE", prebuilt.manifest)
entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion.String())
+ // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
},
},
}}
@@ -295,6 +301,7 @@
if len(binary.dexpreopter.builtInstalled) > 0 {
entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", binary.dexpreopter.builtInstalled)
}
+ entries.SetOptionalPaths("LOCAL_ACONFIG_FILES", binary.getTransitiveAconfigFiles().ToList())
},
},
ExtraFooters: []android.AndroidMkExtraFootersFunc{
@@ -340,6 +347,9 @@
// App module names can be overridden.
entries.SetString("LOCAL_MODULE", app.installApkName)
entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", app.appProperties.PreventInstall)
+ if app.headerJarFile != nil {
+ entries.SetPath("LOCAL_SOONG_HEADER_JAR", app.headerJarFile)
+ }
entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", app.exportPackage)
if app.dexJarFile.IsSet() {
entries.SetPath("LOCAL_SOONG_DEX_JAR", app.dexJarFile.Path())
@@ -437,6 +447,10 @@
}
entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", app.linter.reports)
+
+ if app.Name() != "framework-res" {
+ entries.SetOptionalPaths("LOCAL_ACONFIG_FILES", app.getTransitiveAconfigFiles().ToList())
+ }
},
},
ExtraFooters: []android.AndroidMkExtraFootersFunc{
@@ -455,11 +469,6 @@
if len(a.overridableAppProperties.Overrides) > 0 {
overridden = append(overridden, a.overridableAppProperties.Overrides...)
}
- // When APK name is overridden via PRODUCT_PACKAGE_NAME_OVERRIDES
- // ensure that the original name is overridden.
- if a.Stem() != a.installApkName {
- overridden = append(overridden, a.Stem())
- }
return overridden
}
@@ -513,10 +522,12 @@
}
entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.exportPackage)
+ entries.SetPaths("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", a.transitiveAaptResourcePackages)
entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", a.extraAaptPackagesFile)
entries.SetPath("LOCAL_FULL_MANIFEST_FILE", a.mergedManifestFile)
entries.AddStrings("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", a.exportedProguardFlagFiles.Strings()...)
entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", true)
+ entries.SetOptionalPaths("LOCAL_ACONFIG_FILES", a.getTransitiveAconfigFiles().ToList())
})
return entriesList
@@ -689,6 +700,7 @@
if Bool(a.properties.Export_package_resources) {
entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.outputFile)
}
+ // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
},
},
}}
@@ -722,6 +734,7 @@
entries.SetString("LOCAL_CERTIFICATE", r.certificate.AndroidMkString())
entries.SetPath("LOCAL_MODULE_PATH", r.installDir)
entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", r.properties.Overrides...)
+ // TODO: LOCAL_ACONFIG_FILES -- Might eventually need aconfig flags?
},
},
}}
@@ -739,6 +752,7 @@
entries.SetPath("LOCAL_APK_SET_INSTALL_FILE", apkSet.PackedAdditionalOutputs())
entries.SetPath("LOCAL_APKCERTS_FILE", apkSet.apkcertsFile)
entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", apkSet.properties.Overrides...)
+ // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts -- Both declarations and values
},
},
},
diff --git a/java/app.go b/java/app.go
index a7f894a..7172d22 100755
--- a/java/app.go
+++ b/java/app.go
@@ -521,7 +521,23 @@
a.dexpreopter.preventInstall = a.appProperties.PreventInstall
if ctx.ModuleName() != "framework-res" {
- a.Module.compile(ctx, a.aaptSrcJar)
+ var extraSrcJars android.Paths
+ var extraClasspathJars android.Paths
+ var extraCombinedJars android.Paths
+ if a.useResourceProcessorBusyBox() {
+ // When building an app with ResourceProcessorBusyBox enabled ResourceProcessorBusyBox has already
+ // created R.class files that provide IDs for resources in busybox/R.jar. Pass that file in the
+ // classpath when compiling everything else, and add it to the final classes jar.
+ extraClasspathJars = android.Paths{a.aapt.rJar}
+ extraCombinedJars = android.Paths{a.aapt.rJar}
+ } else {
+ // When building an app without ResourceProcessorBusyBox the aapt2 rule creates R.srcjar containing
+ // R.java files for the app's package and the packages from all transitive static android_library
+ // dependencies. Compile the srcjar alongside the rest of the sources.
+ extraSrcJars = android.Paths{a.aapt.aaptSrcJar}
+ }
+
+ a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
}
return a.dexJarFile.PathOrNil()
@@ -666,8 +682,17 @@
a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx)
a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
+ // Unlike installApkName, a.stem should respect base module name for override_android_app.
+ // Therefore, use ctx.ModuleName() instead of a.Name().
+ a.stem = proptools.StringDefault(a.overridableDeviceProperties.Stem, ctx.ModuleName())
+
// Check if the install APK name needs to be overridden.
- a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(a.Stem())
+ // Both android_app and override_android_app module are expected to possess
+ // its module bound apk path. However, override_android_app inherits ctx.ModuleName()
+ // from the base module. Therefore, use a.Name() which represents
+ // the module name for both android_app and override_android_app.
+ a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(
+ proptools.StringDefault(a.overridableDeviceProperties.Stem, a.Name()))
if ctx.ModuleName() == "framework-res" {
// framework-res.apk is installed as system/framework/framework-res.apk
diff --git a/java/app_builder.go b/java/app_builder.go
index d20a6bf..d397ff7 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -225,8 +225,6 @@
})
}
-const jniJarOutputPathString = "jniJarOutput.zip"
-
func TransformJniLibsToJar(
ctx android.ModuleContext,
outputFile android.WritablePath,
@@ -258,7 +256,10 @@
rule = zipRE
args["implicits"] = strings.Join(deps.Strings(), ",")
}
- jniJarPath := android.PathForModuleOut(ctx, jniJarOutputPathString)
+ var jniJarPath android.WritablePath = android.PathForModuleOut(ctx, "jniJarOutput.zip")
+ if len(prebuiltJniPackages) == 0 {
+ jniJarPath = outputFile
+ }
ctx.Build(pctx, android.BuildParams{
Rule: rule,
Description: "zip jni libs",
@@ -266,12 +267,26 @@
Implicits: deps,
Args: args,
})
- ctx.Build(pctx, android.BuildParams{
- Rule: mergeAssetsRule,
- Description: "merge prebuilt JNI packages",
- Inputs: append(prebuiltJniPackages, jniJarPath),
- Output: outputFile,
- })
+ if len(prebuiltJniPackages) > 0 {
+ var mergeJniJarPath android.WritablePath = android.PathForModuleOut(ctx, "mergeJniJarOutput.zip")
+ if !uncompressJNI {
+ mergeJniJarPath = outputFile
+ }
+ ctx.Build(pctx, android.BuildParams{
+ Rule: mergeAssetsRule,
+ Description: "merge prebuilt JNI packages",
+ Inputs: append(prebuiltJniPackages, jniJarPath),
+ Output: mergeJniJarPath,
+ })
+
+ if uncompressJNI {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: uncompressEmbeddedJniLibsRule,
+ Input: mergeJniJarPath,
+ Output: outputFile,
+ })
+ }
+ }
}
func (a *AndroidApp) generateJavaUsedByApex(ctx android.ModuleContext) {
diff --git a/java/app_import.go b/java/app_import.go
index e25bcd1..ad1765e 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -51,9 +51,9 @@
Description: "Uncompress dex files",
})
- checkJniAndDexLibsAreUncompressedRule = pctx.AndroidStaticRule("check-jni-and-dex-libs-are-uncompressed", blueprint.RuleParams{
+ checkDexLibsAreUncompressedRule = pctx.AndroidStaticRule("check-dex-libs-are-uncompressed", blueprint.RuleParams{
// grep -v ' stor ' will search for lines that don't have ' stor '. stor means the file is stored uncompressed
- Command: "if (zipinfo $in 'lib/*.so' '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then " +
+ Command: "if (zipinfo $in '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then " +
"echo $in: Contains compressed JNI libraries and/or dex files >&2;" +
"exit 1; " +
"else " +
@@ -61,6 +61,17 @@
"fi",
Description: "Check for compressed JNI libs or dex files",
})
+
+ checkJniLibsAreUncompressedRule = pctx.AndroidStaticRule("check-jni-libs-are-uncompressed", blueprint.RuleParams{
+ // grep -v ' stor ' will search for lines that don't have ' stor '. stor means the file is stored uncompressed
+ Command: "if (zipinfo $in 'lib/*.so' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then " +
+ "echo $in: Contains compressed JNI libraries >&2;" +
+ "exit 1; " +
+ "else " +
+ "touch $out; " +
+ "fi",
+ Description: "Check for compressed JNI libs or dex files",
+ })
)
func RegisterAppImportBuildComponents(ctx android.RegistrationContext) {
@@ -384,26 +395,40 @@
}
func (a *AndroidAppImport) validatePreprocessedApk(ctx android.ModuleContext, srcApk android.Path, dstApk android.WritablePath) {
+ var validations android.Paths
+
alignmentStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "alignment.stamp")
ctx.Build(pctx, android.BuildParams{
Rule: checkZipAlignment,
Input: srcApk,
Output: alignmentStamp,
})
- compressionStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "compression.stamp")
+
+ validations = append(validations, alignmentStamp)
+ jniCompressionStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "jni_compression.stamp")
ctx.Build(pctx, android.BuildParams{
- Rule: checkJniAndDexLibsAreUncompressedRule,
+ Rule: checkJniLibsAreUncompressedRule,
Input: srcApk,
- Output: compressionStamp,
+ Output: jniCompressionStamp,
})
+ validations = append(validations, jniCompressionStamp)
+
+ if a.Privileged() {
+ // It's ok for non-privileged apps to have compressed dex files, see go/gms-uncompressed-jni-slides
+ dexCompressionStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "dex_compression.stamp")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: checkDexLibsAreUncompressedRule,
+ Input: srcApk,
+ Output: dexCompressionStamp,
+ })
+ validations = append(validations, dexCompressionStamp)
+ }
+
ctx.Build(pctx, android.BuildParams{
- Rule: android.Cp,
- Input: srcApk,
- Output: dstApk,
- Validations: []android.Path{
- alignmentStamp,
- compressionStamp,
- },
+ Rule: android.Cp,
+ Input: srcApk,
+ Output: dstApk,
+ Validations: validations,
})
}
diff --git a/java/app_test.go b/java/app_test.go
index c438b6c..8474ea7 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -722,7 +722,10 @@
func TestAndroidResourceProcessor(t *testing.T) {
testCases := []struct {
- name string
+ name string
+ appUsesRP bool
+ directLibUsesRP bool
+ transitiveLibUsesRP bool
dontVerifyApp bool
appResources []string
@@ -759,7 +762,12 @@
transitiveImportImports []string
}{
{
- name: "legacy",
+ // Test with all modules set to use_resource_processor: false (except android_library_import modules,
+ // which always use resource processor).
+ name: "legacy",
+ appUsesRP: false,
+ directLibUsesRP: false,
+ transitiveLibUsesRP: false,
appResources: nil,
appOverlays: []string{
@@ -771,7 +779,6 @@
"out/soong/.intermediates/direct_import/android_common/package-res.apk",
"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
},
-
appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"},
appClasspath: []string{
@@ -792,7 +799,6 @@
"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat",
},
-
directImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
directSrcJars: []string{"out/soong/.intermediates/direct/android_common/gen/android/R.srcjar"},
directClasspath: []string{
@@ -814,18 +820,256 @@
transitiveCombined: nil,
directImportResources: nil,
- directImportOverlays: []string{
- "out/soong/.intermediates/direct_import/android_common/flat-res/gen_res.flata",
+ directImportOverlays: []string{"out/soong/.intermediates/direct_import/android_common/flat-res/gen_res.flata"},
+ directImportImports: []string{
+ "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
},
- directImportImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
transitiveImportResources: nil,
- transitiveImportOverlays: []string{
- "out/soong/.intermediates/transitive_import/android_common/flat-res/gen_res.flata",
+ transitiveImportOverlays: []string{"out/soong/.intermediates/transitive_import/android_common/flat-res/gen_res.flata"},
+ transitiveImportImports: []string{
+ "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
},
- transitiveImportImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+ },
+ {
+ // Test with all modules set to use_resource_processor: true.
+ name: "resource_processor",
+ appUsesRP: true,
+ directLibUsesRP: true,
+ transitiveLibUsesRP: true,
+
+ appResources: nil,
+ appOverlays: []string{
+ "out/soong/.intermediates/transitive/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+ "out/soong/.intermediates/direct/android_common/package-res.apk",
+ "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+ "out/soong/.intermediates/direct_import/android_common/package-res.apk",
+ "out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
+ },
+ appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+ appSrcJars: nil,
+ appClasspath: []string{
+ "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+ "out/soong/.intermediates/app/android_common/busybox/R.jar",
+ "out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
+ "out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+ },
+ appCombined: []string{
+ "out/soong/.intermediates/app/android_common/busybox/R.jar",
+ "out/soong/.intermediates/app/android_common/javac/app.jar",
+ "out/soong/.intermediates/direct/android_common/combined/direct.jar",
+ "out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+ },
+
+ directResources: nil,
+ directOverlays: []string{"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat"},
+ directImports: []string{
+ "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive/android_common/package-res.apk",
+ },
+ directSrcJars: nil,
+ directClasspath: []string{
+ "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+ "out/soong/.intermediates/transitive_import/android_common/busybox/R.jar",
+ "out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar",
+ "out/soong/.intermediates/transitive/android_common/busybox/R.jar",
+ "out/soong/.intermediates/direct/android_common/busybox/R.jar",
+ "out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
+ "out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+ },
+ directCombined: []string{
+ "out/soong/.intermediates/direct/android_common/javac/direct.jar",
+ "out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
+ "out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+ },
+
+ transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"},
+ transitiveOverlays: nil,
+ transitiveImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+ transitiveSrcJars: nil,
+ transitiveClasspath: []string{
+ "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+ "out/soong/.intermediates/transitive/android_common/busybox/R.jar",
+ },
+ transitiveCombined: nil,
+
+ directImportResources: nil,
+ directImportOverlays: []string{"out/soong/.intermediates/direct_import/android_common/flat-res/gen_res.flata"},
+ directImportImports: []string{
+ "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+ "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+ },
+
+ transitiveImportResources: nil,
+ transitiveImportOverlays: []string{"out/soong/.intermediates/transitive_import/android_common/flat-res/gen_res.flata"},
+ transitiveImportImports: []string{
+ "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+ },
+ }, {
+ // Test an app building with resource processor enabled but with dependencies built without
+ // resource processor.
+ name: "app_resource_processor",
+ appUsesRP: true,
+ directLibUsesRP: false,
+ transitiveLibUsesRP: false,
+
+ appResources: nil,
+ appOverlays: []string{
+ "out/soong/.intermediates/transitive/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+ "out/soong/.intermediates/direct/android_common/package-res.apk",
+ "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+ "out/soong/.intermediates/direct_import/android_common/package-res.apk",
+ "out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
+ },
+ appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+ appSrcJars: nil,
+ appClasspath: []string{
+ "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+ // R.jar has to come before direct.jar
+ "out/soong/.intermediates/app/android_common/busybox/R.jar",
+ "out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
+ "out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+ },
+ appCombined: []string{
+ "out/soong/.intermediates/app/android_common/busybox/R.jar",
+ "out/soong/.intermediates/app/android_common/javac/app.jar",
+ "out/soong/.intermediates/direct/android_common/combined/direct.jar",
+ "out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+ },
+
+ dontVerifyDirect: true,
+ dontVerifyTransitive: true,
+ dontVerifyDirectImport: true,
+ dontVerifyTransitiveImport: true,
+ },
+ {
+ // Test an app building without resource processor enabled but with a dependency built with
+ // resource processor.
+ name: "app_dependency_lib_resource_processor",
+ appUsesRP: false,
+ directLibUsesRP: true,
+ transitiveLibUsesRP: false,
+
+ appOverlays: []string{
+ "out/soong/.intermediates/transitive/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+ "out/soong/.intermediates/direct/android_common/package-res.apk",
+ "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+ "out/soong/.intermediates/direct_import/android_common/package-res.apk",
+ "out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
+ },
+ appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+ appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"},
+ appClasspath: []string{
+ "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+ "out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
+ "out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+ },
+ appCombined: []string{
+ "out/soong/.intermediates/app/android_common/javac/app.jar",
+ "out/soong/.intermediates/direct/android_common/combined/direct.jar",
+ "out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+ },
+
+ directResources: nil,
+ directOverlays: []string{"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat"},
+ directImports: []string{
+ "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive/android_common/package-res.apk",
+ },
+ directSrcJars: nil,
+ directClasspath: []string{
+ "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+ "out/soong/.intermediates/transitive_import/android_common/busybox/R.jar",
+ "out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar",
+ "out/soong/.intermediates/direct/android_common/busybox/R.jar",
+ "out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
+ "out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+ },
+ directCombined: []string{
+ "out/soong/.intermediates/direct/android_common/javac/direct.jar",
+ "out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
+ "out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+ },
+
+ dontVerifyTransitive: true,
+ dontVerifyDirectImport: true,
+ dontVerifyTransitiveImport: true,
+ },
+ {
+ // Test a library building without resource processor enabled but with a dependency built with
+ // resource processor.
+ name: "lib_dependency_lib_resource_processor",
+ appUsesRP: false,
+ directLibUsesRP: false,
+ transitiveLibUsesRP: true,
+
+ appOverlays: []string{
+ "out/soong/.intermediates/transitive/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+ "out/soong/.intermediates/direct/android_common/package-res.apk",
+ "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+ "out/soong/.intermediates/direct_import/android_common/package-res.apk",
+ "out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
+ },
+ appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+ appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"},
+ appClasspath: []string{
+ "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+ "out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
+ "out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+ },
+ appCombined: []string{
+ "out/soong/.intermediates/app/android_common/javac/app.jar",
+ "out/soong/.intermediates/direct/android_common/combined/direct.jar",
+ "out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+ },
+
+ directResources: nil,
+ directOverlays: []string{
+ "out/soong/.intermediates/transitive/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+ "out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+ "out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat",
+ },
+ directImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+ directSrcJars: []string{"out/soong/.intermediates/direct/android_common/gen/android/R.srcjar"},
+ directClasspath: []string{
+ "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+ "out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
+ "out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+ },
+ directCombined: []string{
+ "out/soong/.intermediates/direct/android_common/javac/direct.jar",
+ "out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
+ "out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+ },
+
+ transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"},
+ transitiveOverlays: nil,
+ transitiveImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+ transitiveSrcJars: nil,
+ transitiveClasspath: []string{
+ "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+ "out/soong/.intermediates/transitive/android_common/busybox/R.jar",
+ },
+ transitiveCombined: nil,
+
+ dontVerifyDirectImport: true,
+ dontVerifyTransitiveImport: true,
},
}
@@ -839,6 +1083,7 @@
resource_dirs: ["app/res"],
manifest: "app/AndroidManifest.xml",
static_libs: ["direct", "direct_import"],
+ use_resource_processor: %v,
}
android_library {
@@ -848,6 +1093,7 @@
resource_dirs: ["direct/res"],
manifest: "direct/AndroidManifest.xml",
static_libs: ["transitive", "transitive_import"],
+ use_resource_processor: %v,
}
android_library {
@@ -856,6 +1102,7 @@
srcs: ["transitive/transitive.java"],
resource_dirs: ["transitive/res"],
manifest: "transitive/AndroidManifest.xml",
+ use_resource_processor: %v,
}
android_library_import {
@@ -883,7 +1130,7 @@
sdk_version: "current",
aars: ["transitive_import_dep.aar"],
}
- `)
+ `, testCase.appUsesRP, testCase.directLibUsesRP, testCase.transitiveLibUsesRP)
fs := android.MockFS{
"app/res/values/strings.xml": nil,
@@ -1495,7 +1742,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
app := ctx.ModuleForTests(test.name, "android_common")
- jniLibZip := app.Output(jniJarOutputPathString)
+ jniLibZip := app.Output("jnilibs.zip")
var abis []string
args := strings.Fields(jniLibZip.Args["jarArgs"])
for i := 0; i < len(args); i++ {
@@ -1628,7 +1875,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
app := ctx.ModuleForTests(test.name, "android_common")
- jniLibZip := app.MaybeOutput(jniJarOutputPathString)
+ jniLibZip := app.MaybeOutput("jnilibs.zip")
if g, w := (jniLibZip.Rule != nil), test.packaged; g != w {
t.Errorf("expected jni packaged %v, got %v", w, g)
}
@@ -1719,7 +1966,7 @@
t.Run(test.name, func(t *testing.T) {
app := ctx.ModuleForTests(test.name, "android_common")
- jniLibZip := app.MaybeOutput(jniJarOutputPathString)
+ jniLibZip := app.MaybeOutput("jnilibs.zip")
if len(jniLibZip.Implicits) != 1 {
t.Fatalf("expected exactly one jni library, got %q", jniLibZip.Implicits.Strings())
}
@@ -2739,7 +2986,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
app := ctx.ModuleForTests(test.name, "android_common")
- jniLibZip := app.Output(jniJarOutputPathString)
+ jniLibZip := app.Output("jnilibs.zip")
var jnis []string
args := strings.Fields(jniLibZip.Args["jarArgs"])
for i := 0; i < len(args); i++ {
diff --git a/java/base.go b/java/base.go
index cb08ef3..f5eb01c 100644
--- a/java/base.go
+++ b/java/base.go
@@ -21,6 +21,7 @@
"strings"
"android/soong/ui/metrics/bp2build_metrics_proto"
+
"github.com/google/blueprint/pathtools"
"github.com/google/blueprint/proptools"
@@ -502,6 +503,19 @@
sourceExtensions []string
annoSrcJars android.Paths
+
+ // output file name based on Stem property.
+ // This should be set in every ModuleWithStem's GenerateAndroidBuildActions
+ // or the module should override Stem().
+ stem string
+
+ // Aconfig "cache files" that went directly into this module. Transitive ones are
+ // tracked via JavaInfo.TransitiveAconfigFiles
+ // TODO: Extract to something standalone to propagate tags via GeneratedJavaLibraryModule
+ aconfigIntermediates android.Paths
+
+ // Aconfig files for all transitive deps. Also exposed via JavaInfo
+ transitiveAconfigFiles *android.DepSet[android.Path]
}
func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
@@ -1051,7 +1065,7 @@
module.properties.Generated_srcjars = append(module.properties.Generated_srcjars, path)
}
-func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
+func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars android.Paths) {
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
deps := j.collectDeps(ctx)
@@ -1089,9 +1103,7 @@
srcJars := srcFiles.FilterByExt(".srcjar")
srcJars = append(srcJars, deps.srcJars...)
- if aaptSrcJar != nil {
- srcJars = append(srcJars, aaptSrcJar)
- }
+ srcJars = append(srcJars, extraSrcJars...)
srcJars = append(srcJars, j.properties.Generated_srcjars...)
srcFiles = srcFiles.FilterOutByExt(".srcjar")
@@ -1099,7 +1111,7 @@
j.expandJarjarRules = android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
}
- jarName := ctx.ModuleName() + ".jar"
+ jarName := j.Stem() + ".jar"
var uniqueJavaFiles android.Paths
set := make(map[string]bool)
@@ -1134,6 +1146,11 @@
var kotlinJars android.Paths
var kotlinHeaderJars android.Paths
+ // Prepend extraClasspathJars to classpath so that the resource processor R.jar comes before
+ // any dependencies so that it can override any non-final R classes from dependencies with the
+ // final R classes from the app.
+ flags.classpath = append(android.CopyOf(extraClasspathJars), flags.classpath...)
+
if srcFiles.HasExt(".kt") {
// When using kotlin sources turbine is used to generate annotation processor sources,
// including for annotation processors that generate API, so we can use turbine for
@@ -1227,8 +1244,9 @@
// allow for the use of annotation processors that do function correctly
// with sharding enabled. See: b/77284273.
}
+ extraJars := append(android.CopyOf(extraCombinedJars), kotlinHeaderJars...)
headerJarFileWithoutDepsOrJarjar, j.headerJarFile =
- j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, kotlinHeaderJars)
+ j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars)
if ctx.Failed() {
return
}
@@ -1379,6 +1397,8 @@
jars = append(jars, servicesJar)
}
+ jars = append(android.CopyOf(extraCombinedJars), jars...)
+
// Combine the classes built from sources, any manifests, and any static libraries into
// classes.jar. If there is only one input jar this step will be skipped.
var outputFile android.OutputPath
@@ -1471,7 +1491,13 @@
j.implementationJarFile = outputFile
if j.headerJarFile == nil {
- j.headerJarFile = j.implementationJarFile
+ // If this module couldn't generate a header jar (for example due to api generating annotation processors)
+ // then use the implementation jar. Run it through zip2zip first to remove any files in META-INF/services
+ // so that javac on modules that depend on this module don't pick up annotation processors (which may be
+ // missing their implementations) from META-INF/services/javax.annotation.processing.Processor.
+ headerJarFile := android.PathForModuleOut(ctx, "javac-header", jarName)
+ convertImplementationJarToHeaderJar(ctx, j.implementationJarFile, headerJarFile)
+ j.headerJarFile = headerJarFile
}
// enforce syntax check to jacoco filters for any build (http://b/183622051)
@@ -1617,6 +1643,8 @@
ctx.CheckbuildFile(outputFile)
+ j.collectTransitiveAconfigFiles(ctx)
+
ctx.SetProvider(JavaInfoProvider, JavaInfo{
HeaderJars: android.PathsIfNonNil(j.headerJarFile),
TransitiveLibsHeaderJars: j.transitiveLibsHeaderJars,
@@ -1631,6 +1659,7 @@
ExportedPluginClasses: j.exportedPluginClasses,
ExportedPluginDisableTurbine: j.exportedDisableTurbine,
JacocoReportClassesFile: j.jacocoReportClassesFile,
+ TransitiveAconfigFiles: j.transitiveAconfigFiles,
})
// Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource
@@ -1897,7 +1926,10 @@
}
func (j *Module) Stem() string {
- return proptools.StringDefault(j.overridableDeviceProperties.Stem, j.Name())
+ if j.stem == "" {
+ panic("Stem() called before stem property was set")
+ }
+ return j.stem
}
func (j *Module) JacocoReportClassesFile() android.Path {
@@ -1908,6 +1940,34 @@
return Bool(j.properties.Installable)
}
+func (j *Module) collectTransitiveAconfigFiles(ctx android.ModuleContext) {
+ // Aconfig files from this module
+ mine := j.aconfigIntermediates
+
+ // Aconfig files from transitive dependencies
+ fromDeps := []*android.DepSet[android.Path]{}
+ ctx.VisitDirectDeps(func(module android.Module) {
+ dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+ if dep.TransitiveAconfigFiles != nil {
+ fromDeps = append(fromDeps, dep.TransitiveAconfigFiles)
+ }
+ })
+
+ // DepSet containing aconfig files myself and from dependencies
+ j.transitiveAconfigFiles = android.NewDepSet(android.POSTORDER, mine, fromDeps)
+}
+
+func (j *Module) AddAconfigIntermediate(path android.Path) {
+ j.aconfigIntermediates = append(j.aconfigIntermediates, path)
+}
+
+func (j *Module) getTransitiveAconfigFiles() *android.DepSet[android.Path] {
+ if j.transitiveAconfigFiles == nil {
+ panic(fmt.Errorf("java.Moduile: getTransitiveAconfigFiles called before collectTransitiveAconfigFiles module=%s", j.Name()))
+ }
+ return j.transitiveAconfigFiles
+}
+
type sdkLinkType int
const (
diff --git a/java/builder.go b/java/builder.go
index be4af55..debf49a 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -42,7 +42,7 @@
// TODO(b/143658984): goma can't handle the --system argument to javac.
javac, javacRE = pctx.MultiCommandRemoteStaticRules("javac",
blueprint.RuleParams{
- Command: `rm -rf "$outDir" "$annoDir" "$annoSrcJar" "$srcJarDir" "$out" && ` +
+ Command: `rm -rf "$outDir" "$annoDir" "$annoSrcJar.tmp" "$srcJarDir" "$out.tmp" && ` +
`mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
`(if [ -s $srcJarDir/list ] || [ -s $out.rsp ] ; then ` +
@@ -51,15 +51,18 @@
`$processorpath $processor $javacFlags $bootClasspath $classpath ` +
`-source $javaVersion -target $javaVersion ` +
`-d $outDir -s $annoDir @$out.rsp @$srcJarDir/list ; fi ) && ` +
- `$annoSrcJarTemplate${config.SoongZipCmd} -jar -o $annoSrcJar -C $annoDir -D $annoDir && ` +
- `$zipTemplate${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir && ` +
- `rm -rf "$srcJarDir"`,
+ `$annoSrcJarTemplate${config.SoongZipCmd} -jar -o $annoSrcJar.tmp -C $annoDir -D $annoDir && ` +
+ `$zipTemplate${config.SoongZipCmd} -jar -o $out.tmp -C $outDir -D $outDir && ` +
+ `if ! cmp -s "$out.tmp" "$out"; then mv "$out.tmp" "$out"; fi && ` +
+ `if ! cmp -s "$annoSrcJar.tmp" "$annoSrcJar"; then mv "$annoSrcJar.tmp" "$annoSrcJar"; fi && ` +
+ `rm -rf "$srcJarDir" "$outDir"`,
CommandDeps: []string{
"${config.JavacCmd}",
"${config.SoongZipCmd}",
"${config.ZipSyncCmd}",
},
CommandOrderOnly: []string{"${config.SoongJavacWrapper}"},
+ Restat: true,
Rspfile: "$out.rsp",
RspfileContent: "$in",
}, map[string]*remoteexec.REParams{
@@ -71,14 +74,14 @@
"$zipTemplate": &remoteexec.REParams{
Labels: map[string]string{"type": "tool", "name": "soong_zip"},
Inputs: []string{"${config.SoongZipCmd}", "$outDir"},
- OutputFiles: []string{"$out"},
+ OutputFiles: []string{"$out.tmp"},
ExecStrategy: "${config.REJavacExecStrategy}",
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
},
"$annoSrcJarTemplate": &remoteexec.REParams{
Labels: map[string]string{"type": "tool", "name": "soong_zip"},
Inputs: []string{"${config.SoongZipCmd}", "$annoDir"},
- OutputFiles: []string{"$annoSrcJar"},
+ OutputFiles: []string{"$annoSrcJar.tmp"},
ExecStrategy: "${config.REJavacExecStrategy}",
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
},
@@ -268,6 +271,12 @@
Description: "Check zip alignment",
},
)
+
+ convertImplementationJarToHeaderJarRule = pctx.AndroidStaticRule("convertImplementationJarToHeaderJar",
+ blueprint.RuleParams{
+ Command: `${config.Zip2ZipCmd} -i ${in} -o ${out} -x 'META-INF/services/**/*'`,
+ CommandDeps: []string{"${config.Zip2ZipCmd}"},
+ })
)
func init() {
@@ -630,6 +639,15 @@
})
}
+func convertImplementationJarToHeaderJar(ctx android.ModuleContext, implementationJarFile android.Path,
+ headerJarFile android.WritablePath) {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: convertImplementationJarToHeaderJarRule,
+ Input: implementationJarFile,
+ Output: headerJarFile,
+ })
+}
+
func TransformJarJar(ctx android.ModuleContext, outputFile android.WritablePath,
classesJar android.Path, rulesFile android.Path) {
ctx.Build(pctx, android.BuildParams{
diff --git a/java/config/config.go b/java/config/config.go
index 195dae1..83c27d3 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -148,6 +148,8 @@
pctx.SourcePathVariable("JavaKytheExtractorJar", "prebuilts/build-tools/common/framework/javac_extractor.jar")
pctx.SourcePathVariable("Ziptime", "prebuilts/build-tools/${hostPrebuiltTag}/bin/ziptime")
+ pctx.SourcePathVariable("ResourceProcessorBusyBox", "prebuilts/bazel/common/android_tools/android_tools/all_android_tools_deploy.jar")
+
pctx.HostBinToolVariable("GenKotlinBuildFileCmd", "gen-kotlin-build-file")
pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh")
diff --git a/java/core-libraries/Android.bp b/java/core-libraries/Android.bp
index eadd9c6..de9a82d 100644
--- a/java/core-libraries/Android.bp
+++ b/java/core-libraries/Android.bp
@@ -146,12 +146,43 @@
],
}
+java_defaults {
+ name: "core.module_lib.stubs.defaults",
+ visibility: ["//visibility:private"],
+ sdk_version: "none",
+ system_modules: "none",
+}
+
+
// A stubs target containing the parts of the public SDK & @SystemApi(MODULE_LIBRARIES) API
// provided by the core libraries.
//
// Don't use this directly, use "sdk_version: module_current".
java_library {
name: "core.module_lib.stubs",
+ defaults: [
+ "core.module_lib.stubs.defaults",
+ ],
+ static_libs: [
+ "core.module_lib.stubs.from-source",
+ ],
+ product_variables: {
+ build_from_text_stub: {
+ static_libs: [
+ "core.module_lib.stubs.from-text",
+ ],
+ exclude_static_libs: [
+ "core.module_lib.stubs.from-source",
+ ],
+ },
+ },
+}
+
+java_library {
+ name: "core.module_lib.stubs.from-source",
+ defaults: [
+ "core.module_lib.stubs.defaults",
+ ],
static_libs: [
"art.module.public.api.stubs.module_lib",
@@ -161,9 +192,6 @@
"conscrypt.module.public.api.stubs",
"i18n.module.public.api.stubs",
],
- sdk_version: "none",
- system_modules: "none",
- visibility: ["//visibility:private"],
}
// Produces a dist file that is used by the
@@ -249,10 +277,10 @@
product_variables: {
build_from_text_stub: {
static_libs: [
- "stable.core.platform.api.stubs.from-text",
+ "legacy.core.platform.api.stubs.from-text",
],
exclude_static_libs: [
- "stable.core.platform.api.stubs.from-source",
+ "legacy.core.platform.api.stubs.from-source",
],
},
},
diff --git a/java/core-libraries/TxtStubLibraries.bp b/java/core-libraries/TxtStubLibraries.bp
index 0cf0f36..c46f8b8 100644
--- a/java/core-libraries/TxtStubLibraries.bp
+++ b/java/core-libraries/TxtStubLibraries.bp
@@ -57,19 +57,23 @@
],
}
-java_library {
+java_api_library {
name: "core.module_lib.stubs.from-text",
- static_libs: [
- "art.module.public.api.stubs.module_lib.from-text",
+ api_surface: "module-lib",
+ api_contributions: [
+ "art.module.public.api.stubs.source.api.contribution",
+ "art.module.public.api.stubs.source.system.api.contribution",
+ "art.module.public.api.stubs.source.module_lib.api.contribution",
- // Replace the following with the module-lib correspondence when Conscrypt or i18N module
+ // Add the module-lib correspondence when Conscrypt or i18N module
// provides @SystemApi(MODULE_LIBRARIES). Currently, assume that only ART module provides
// @SystemApi(MODULE_LIBRARIES).
- "conscrypt.module.public.api.stubs.from-text",
- "i18n.module.public.api.stubs.from-text",
+ "conscrypt.module.public.api.stubs.source.api.contribution",
+ "i18n.module.public.api.stubs.source.api.contribution",
],
- sdk_version: "none",
- system_modules: "none",
+ libs: [
+ "stub-annotations",
+ ],
visibility: ["//visibility:private"],
}
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 3581040..5460dc9 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -143,6 +143,8 @@
ResourceJars: d.resourceJars,
SrcJarArgs: d.srcJarArgs,
SrcJarDeps: d.srcJarDeps,
+ // TODO: Not sure if aconfig flags that have been moved between device and host variants
+ // make sense.
})
}
diff --git a/java/device_host_converter_test.go b/java/device_host_converter_test.go
index 3c9a0f3..3413da0 100644
--- a/java/device_host_converter_test.go
+++ b/java/device_host_converter_test.go
@@ -135,6 +135,7 @@
hostModule := ctx.ModuleForTests("host_module", config.BuildOSCommonTarget.String())
hostJavac := hostModule.Output("javac/host_module.jar")
+ hostJavacHeader := hostModule.Output("javac-header/host_module.jar")
hostRes := hostModule.Output("res/host_module.jar")
hostImportModule := ctx.ModuleForTests("host_import_module", config.BuildOSCommonTarget.String())
@@ -148,7 +149,7 @@
// check classpath of device module with dependency on host_for_device_module
expectedClasspath := "-classpath " + strings.Join(android.Paths{
- hostJavac.Output,
+ hostJavacHeader.Output,
hostImportCombined.Output,
}.Strings(), ":")
diff --git a/java/fuzz_test.go b/java/fuzz_test.go
index dd1e96b..f29c913 100644
--- a/java/fuzz_test.go
+++ b/java/fuzz_test.go
@@ -71,8 +71,8 @@
}
baz := result.ModuleForTests("baz", osCommonTarget).Rule("javac").Output.String()
- barOut := filepath.Join("out", "soong", ".intermediates", "bar", osCommonTarget, "javac", "bar.jar")
- bazOut := filepath.Join("out", "soong", ".intermediates", "baz", osCommonTarget, "javac", "baz.jar")
+ barOut := filepath.Join("out", "soong", ".intermediates", "bar", osCommonTarget, "javac-header", "bar.jar")
+ bazOut := filepath.Join("out", "soong", ".intermediates", "baz", osCommonTarget, "javac-header", "baz.jar")
android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], barOut)
android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], bazOut)
diff --git a/java/generated_java_library.go b/java/generated_java_library.go
index 1b3de9f..f9baa85 100644
--- a/java/generated_java_library.go
+++ b/java/generated_java_library.go
@@ -30,7 +30,7 @@
// Called from inside GenerateAndroidBuildActions. Add the build rules to
// make the srcjar, and return the path to it.
- GenerateSourceJarBuildActions(ctx android.ModuleContext) android.Path
+ GenerateSourceJarBuildActions(module *GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path
}
// GeneratedJavaLibraryModuleFactory provides a utility for modules that are generated
@@ -88,7 +88,7 @@
checkPropertyEmpty(ctx, module, "plugins", module.Library.properties.Plugins)
checkPropertyEmpty(ctx, module, "exported_plugins", module.Library.properties.Exported_plugins)
- srcJarPath := module.callbacks.GenerateSourceJarBuildActions(ctx)
+ srcJarPath := module.callbacks.GenerateSourceJarBuildActions(module, ctx)
module.Library.properties.Generated_srcjars = append(module.Library.properties.Generated_srcjars, srcJarPath)
module.Library.GenerateAndroidBuildActions(ctx)
}
diff --git a/java/generated_java_library_test.go b/java/generated_java_library_test.go
index 68f1f7e..7f52fd1 100644
--- a/java/generated_java_library_test.go
+++ b/java/generated_java_library_test.go
@@ -36,7 +36,8 @@
func (callbacks *JavaGenLibTestCallbacks) DepsMutator(module *GeneratedJavaLibraryModule, ctx android.BottomUpMutatorContext) {
}
-func (callbacks *JavaGenLibTestCallbacks) GenerateSourceJarBuildActions(ctx android.ModuleContext) android.Path {
+func (callbacks *JavaGenLibTestCallbacks) GenerateSourceJarBuildActions(module *GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path {
+ module.AddAconfigIntermediate(android.PathForOutput(ctx, "aconfig_cache_file"))
return android.PathForOutput(ctx, "blah.srcjar")
}
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index d25096b..4d08b83 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -106,7 +106,7 @@
h.uncompressDexState = uncompressedDexState
// If hiddenapi processing is disabled treat this as inactive.
- if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+ if ctx.Config().DisableHiddenApiChecks() {
return
}
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 714634f..8ec1797 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -121,8 +121,8 @@
// hiddenAPI singleton rules
func (h *hiddenAPISingleton) GenerateBuildActions(ctx android.SingletonContext) {
- // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true
- if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+ // Don't run any hiddenapi rules if hiddenapi checks are disabled
+ if ctx.Config().DisableHiddenApiChecks() {
return
}
diff --git a/java/java.go b/java/java.go
index 011dc1c..f29f738 100644
--- a/java/java.go
+++ b/java/java.go
@@ -274,7 +274,14 @@
// instrumented by jacoco.
JacocoReportClassesFile android.Path
- // TODO: Add device config declarations here?
+ // set of aconfig flags for all transitive libs deps
+ // TODO(joeo): It would be nice if this were over in the aconfig package instead of here.
+ // In order to do that, generated_java_library would need a way doing
+ // collectTransitiveAconfigFiles with one of the callbacks, and having that automatically
+ // propagated. If we were to clean up more of the stuff on JavaInfo that's not part of
+ // core java rules (e.g. AidlIncludeDirs), then maybe adding more framework to do that would be
+ // worth it.
+ TransitiveAconfigFiles *android.DepSet[android.Path]
}
var JavaInfoProvider = blueprint.NewProvider(JavaInfo{})
@@ -676,6 +683,8 @@
j.minSdkVersion = j.MinSdkVersion(ctx)
j.maxSdkVersion = j.MaxSdkVersion(ctx)
+ j.stem = proptools.StringDefault(j.overridableDeviceProperties.Stem, ctx.ModuleName())
+
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if !apexInfo.IsForPlatform() {
j.hideApexVariantFromMake = true
@@ -690,7 +699,7 @@
j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
j.classLoaderContexts = j.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
}
- j.compile(ctx, nil)
+ j.compile(ctx, nil, nil, nil)
// Collect the module directory for IDE info in java/jdeps.go.
j.modulePaths = append(j.modulePaths, ctx.ModuleDir())
@@ -728,6 +737,7 @@
}
})
j.exportedProguardFlagFiles = android.FirstUniquePaths(j.exportedProguardFlagFiles)
+
}
func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -1468,6 +1478,8 @@
}
func (j *Binary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ j.stem = proptools.StringDefault(j.overridableDeviceProperties.Stem, ctx.ModuleName())
+
if ctx.Arch().ArchType == android.Common {
// Compile the jar
if j.binaryProperties.Main_class != nil {
@@ -1912,6 +1924,7 @@
ImplementationAndResourcesJars: android.PathsIfNonNil(al.stubsJar),
ImplementationJars: android.PathsIfNonNil(al.stubsJar),
AidlIncludeDirs: android.Paths{},
+ // No aconfig libraries on api libraries
})
}
@@ -2233,6 +2246,7 @@
ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedClasspathFile),
ImplementationJars: android.PathsIfNonNil(j.combinedClasspathFile),
AidlIncludeDirs: j.exportAidlIncludeDirs,
+ // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
})
}
@@ -2653,7 +2667,7 @@
var Bool = proptools.Bool
var BoolDefault = proptools.BoolDefault
var String = proptools.String
-var inList = android.InList
+var inList = android.InList[string]
// Add class loader context (CLC) of a given dependency to the current CLC.
func addCLCFromDep(ctx android.ModuleContext, depModule android.Module,
@@ -2805,12 +2819,8 @@
hasKotlin bool
}
-// Replaces //a/b/my_xsd_config with //a/b/my_xsd_config-java
-func xsdConfigJavaTarget(ctx android.BazelConversionPathContext, mod blueprint.Module) string {
- callback := func(xsd android.XsdConfigBp2buildTargets) string {
- return xsd.JavaBp2buildTargetName()
- }
- return android.XsdConfigBp2buildTarget(ctx, mod, callback)
+func javaXsdTargetName(xsd android.XsdConfigBp2buildTargets) string {
+ return xsd.JavaBp2buildTargetName()
}
// convertLibraryAttrsBp2Build returns a javaCommonAttributes struct with
@@ -2821,21 +2831,14 @@
func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) (*javaCommonAttributes, *bp2BuildJavaInfo) {
var srcs bazel.LabelListAttribute
var deps bazel.LabelListAttribute
- var staticDeps bazel.LabelList
+ var staticDeps bazel.LabelListAttribute
archVariantProps := m.GetArchVariantProperties(ctx, &CommonProperties{})
for axis, configToProps := range archVariantProps {
for config, _props := range configToProps {
if archProps, ok := _props.(*CommonProperties); ok {
- srcsNonXsd, srcsXsd := android.PartitionXsdSrcs(ctx, archProps.Srcs)
- excludeSrcsNonXsd, _ := android.PartitionXsdSrcs(ctx, archProps.Exclude_srcs)
- archSrcs := android.BazelLabelForModuleSrcExcludes(ctx, srcsNonXsd, excludeSrcsNonXsd)
+ archSrcs := android.BazelLabelForModuleSrcExcludes(ctx, archProps.Srcs, archProps.Exclude_srcs)
srcs.SetSelectValue(axis, config, archSrcs)
-
- // Add to static deps
- xsdJavaConfigLibraryLabels := android.BazelLabelForModuleDepsWithFn(ctx, srcsXsd, xsdConfigJavaTarget)
- staticDeps.Append(xsdJavaConfigLibraryLabels)
-
}
}
}
@@ -2843,6 +2846,7 @@
javaSrcPartition := "java"
protoSrcPartition := "proto"
+ xsdSrcPartition := "xsd"
logtagSrcPartition := "logtag"
aidlSrcPartition := "aidl"
kotlinPartition := "kotlin"
@@ -2851,6 +2855,7 @@
logtagSrcPartition: bazel.LabelPartition{Extensions: []string{".logtags", ".logtag"}},
protoSrcPartition: android.ProtoSrcLabelPartition,
aidlSrcPartition: android.AidlSrcLabelPartition,
+ xsdSrcPartition: bazel.LabelPartition{LabelMapper: android.XsdLabelMapper(javaXsdTargetName)},
kotlinPartition: bazel.LabelPartition{Extensions: []string{".kt"}},
})
@@ -2858,6 +2863,8 @@
kotlinSrcs := srcPartitions[kotlinPartition]
javaSrcs.Append(kotlinSrcs)
+ staticDeps.Append(srcPartitions[xsdSrcPartition])
+
if !srcPartitions[logtagSrcPartition].IsEmpty() {
logtagsLibName := m.Name() + "_logtags"
ctx.CreateBazelTargetModule(
@@ -2911,7 +2918,7 @@
},
)
- staticDeps.Add(&bazel.Label{Label: ":" + javaAidlLibName})
+ staticDeps.Append(bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + javaAidlLibName}))
}
var javacopts bazel.StringListAttribute //[]string
@@ -2966,7 +2973,9 @@
// by protoc are included directly in the resulting JAR. Thus upstream dependencies
// that depend on a java_library with proto sources can link directly to the protobuf API,
// and so this should be a static dependency.
- staticDeps.Add(protoDepLabel)
+ if protoDepLabel != nil {
+ staticDeps.Append(bazel.MakeSingleLabelListAttribute(*protoDepLabel))
+ }
depLabels := &javaDependencyLabels{}
depLabels.Deps = deps
@@ -2981,7 +2990,7 @@
}
}
}
- depLabels.StaticDeps.Value.Append(staticDeps)
+ depLabels.StaticDeps.Append(staticDeps)
hasKotlin := !kotlinSrcs.IsEmpty()
commonAttrs.kotlinAttributes = &kotlinAttributes{
@@ -3151,6 +3160,7 @@
type javaTestHostAttributes struct {
*javaCommonAttributes
+ Srcs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
Runtime_deps bazel.LabelListAttribute
}
@@ -3187,8 +3197,10 @@
hasKotlin: bp2BuildInfo.hasKotlin,
}
libName := createLibraryTarget(ctx, libInfo)
- attrs.Runtime_deps.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + libName}})
+ attrs.Srcs = commonAttrs.Srcs
+ attrs.Deps = deps
+ attrs.Runtime_deps.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + libName}})
// Create the BazelTargetModule.
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
}
@@ -3301,7 +3313,8 @@
HeaderJars: android.PathsIfNonNil(i.combinedClasspathFile),
ImplementationAndResourcesJars: android.PathsIfNonNil(i.combinedClasspathFile),
ImplementationJars: android.PathsIfNonNil(i.combinedClasspathFile),
- //TODO(b/240308299) include AIDL information from Bazel
+ // TODO(b/240308299) include AIDL information from Bazel
+ // TODO: aconfig files?
})
i.maybeInstall(ctx, jarName, outputFile)
diff --git a/java/java_test.go b/java/java_test.go
index 4738304..dd98677 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -2351,3 +2351,22 @@
`stable.core.platform.api.stubs`,
})
}
+
+func TestJavaLibraryWithResourcesStem(t *testing.T) {
+ ctx, _ := testJavaWithFS(t, `
+ java_library {
+ name: "foo",
+ java_resource_dirs: ["test-jar"],
+ stem: "test",
+ }
+ `,
+ map[string][]byte{
+ "test-jar/test/resource.txt": nil,
+ })
+
+ m := ctx.ModuleForTests("foo", "android_common")
+ outputs := fmt.Sprint(m.AllOutputs())
+ if !strings.Contains(outputs, "test.jar") {
+ t.Errorf("Module output does not contain expected jar %s", "test.jar")
+ }
+}
diff --git a/java/kotlin.go b/java/kotlin.go
index f28d6c7..3637e2e 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -42,7 +42,7 @@
` -P plugin:org.jetbrains.kotlin.jvm.abi:outputDir=$headerClassesDir && ` +
`${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir -write_if_changed && ` +
`${config.SoongZipCmd} -jar -o $headerJar -C $headerClassesDir -D $headerClassesDir -write_if_changed && ` +
- `rm -rf "$srcJarDir"`,
+ `rm -rf "$srcJarDir" "$classesDir" "$headerClassesDir"`,
CommandDeps: []string{
"${config.KotlincCmd}",
"${config.KotlinCompilerJar}",
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index a4bba48..ade7395 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -113,7 +113,7 @@
}
func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpMutatorContext) {
- if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+ if ctx.Config().DisableHiddenApiChecks() {
return
}
@@ -275,10 +275,10 @@
bootDexJarByModule := extractBootDexJarsFromModules(ctx, modules)
- // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true. This is a performance
+ // Don't run any hiddenapi rules if hidden api checks are disabled. This is a performance
// optimization that can be used to reduce the incremental build time but as its name suggests it
// can be unsafe to use, e.g. when the changes affect anything that goes on the bootclasspath.
- if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+ if ctx.Config().DisableHiddenApiChecks() {
paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV}
for _, path := range paths {
ctx.Build(pctx, android.BuildParams{
diff --git a/python/bp2build.go b/python/bp2build.go
index cd3f2a1..60cabc4 100644
--- a/python/bp2build.go
+++ b/python/bp2build.go
@@ -223,7 +223,8 @@
props := bazel.BazelTargetModuleProperties{
// Use the native py_binary rule.
- Rule_class: "py_test",
+ Rule_class: "py_test",
+ Bzl_load_location: "//build/bazel/rules/python:py_test.bzl",
}
ctx.CreateBazelTargetModule(props, android.CommonAttributes{
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 7dc1b4b..c2bf6af 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -29,7 +29,7 @@
defaultBindgenFlags = []string{""}
// bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
- bindgenClangVersion = "clang-r487747c"
+ bindgenClangVersion = "clang-r498229"
_ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string {
if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" {
@@ -61,15 +61,18 @@
"${cc_config.ClangBase}/${bindgenHostPrebuiltTag}/${bindgenClangVersion}/${bindgenClangLibdir}")
//TODO(ivanlozano) Switch this to RuleBuilder
+ //
+ //TODO Pass the flag files directly to bindgen e.g. with @file when it supports that.
+ //See https://github.com/rust-lang/rust-bindgen/issues/2508.
bindgen = pctx.AndroidStaticRule("bindgen",
blueprint.RuleParams{
Command: "CLANG_PATH=$bindgenClang LIBCLANG_PATH=$bindgenLibClang RUSTFMT=${config.RustBin}/rustfmt " +
- "$cmd $flags $in -o $out -- -MD -MF $out.d $cflags",
+ "$cmd $flags $$(cat $flagfiles) $in -o $out -- -MD -MF $out.d $cflags",
CommandDeps: []string{"$cmd"},
Deps: blueprint.DepsGCC,
Depfile: "$out.d",
},
- "cmd", "flags", "cflags")
+ "cmd", "flags", "flagfiles", "cflags")
)
func init() {
@@ -90,6 +93,9 @@
// list of bindgen-specific flags and options
Bindgen_flags []string `android:"arch_variant"`
+ // list of files containing extra bindgen flags
+ Bindgen_flag_files []string `android:"arch_variant"`
+
// module name of a custom binary/script which should be used instead of the 'bindgen' binary. This custom
// binary must expect arguments in a similar fashion to bindgen, e.g.
//
@@ -216,6 +222,14 @@
bindgenFlags := defaultBindgenFlags
bindgenFlags = append(bindgenFlags, esc(b.Properties.Bindgen_flags)...)
+ // cat reads from stdin if its command line is empty,
+ // so we pass in /dev/null if there are no other flag files
+ bindgenFlagFiles := []string{"/dev/null"}
+ for _, flagFile := range b.Properties.Bindgen_flag_files {
+ bindgenFlagFiles = append(bindgenFlagFiles, android.PathForModuleSrc(ctx, flagFile).String())
+ implicits = append(implicits, android.PathForModuleSrc(ctx, flagFile))
+ }
+
wrapperFile := android.OptionalPathForModuleSrc(ctx, b.Properties.Wrapper_src)
if !wrapperFile.Valid() {
ctx.PropertyErrorf("wrapper_src", "invalid path to wrapper source")
@@ -261,9 +275,10 @@
Input: wrapperFile.Path(),
Implicits: implicits,
Args: map[string]string{
- "cmd": cmd,
- "flags": strings.Join(bindgenFlags, " "),
- "cflags": strings.Join(cflags, " "),
+ "cmd": cmd,
+ "flags": strings.Join(bindgenFlags, " "),
+ "flagfiles": strings.Join(bindgenFlagFiles, " "),
+ "cflags": strings.Join(cflags, " "),
},
})
diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go
index af04cfc..12cdb3c 100644
--- a/rust/bindgen_test.go
+++ b/rust/bindgen_test.go
@@ -168,3 +168,28 @@
}
`)
}
+
+func TestBindgenFlagFile(t *testing.T) {
+ ctx := testRust(t, `
+ rust_bindgen {
+ name: "libbindgen",
+ wrapper_src: "src/any.h",
+ crate_name: "bindgen",
+ stem: "libbindgen",
+ source_stem: "bindings",
+ bindgen_flag_files: [
+ "flag_file.txt",
+ ],
+ }
+ `)
+ libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs")
+
+ if !strings.Contains(libbindgen.Args["flagfiles"], "/dev/null") {
+ t.Errorf("missing /dev/null in rust_bindgen rule: flags %#v", libbindgen.Args["flagfiles"])
+ }
+ if !strings.Contains(libbindgen.Args["flagfiles"], "flag_file.txt") {
+ t.Errorf("missing bindgen flags file in rust_bindgen rule: flags %#v", libbindgen.Args["flagfiles"])
+ }
+ // TODO: The best we can do right now is check $flagfiles. Once bindgen.go switches to RuleBuilder,
+ // we may be able to check libbinder.RuleParams.Command to see if it contains $(cat /dev/null flag_file.txt)
+}
diff --git a/rust/builder.go b/rust/builder.go
index c31bc88..fbceecc 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -228,6 +228,17 @@
pkgVersion := ctx.RustModule().compiler.CargoPkgVersion()
if pkgVersion != "" {
envVars = append(envVars, "CARGO_PKG_VERSION="+pkgVersion)
+
+ // Ensure the version is in the form of "x.y.z" (approximately semver compliant).
+ //
+ // For our purposes, we don't care to enforce that these are integers since they may
+ // include other characters at times (e.g. sometimes the patch version is more than an integer).
+ if strings.Count(pkgVersion, ".") == 2 {
+ var semver_parts = strings.Split(pkgVersion, ".")
+ envVars = append(envVars, "CARGO_PKG_VERSION_MAJOR="+semver_parts[0])
+ envVars = append(envVars, "CARGO_PKG_VERSION_MINOR="+semver_parts[1])
+ envVars = append(envVars, "CARGO_PKG_VERSION_PATCH="+semver_parts[2])
+ }
}
}
diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go
index ae783e8..08ac2ef 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -26,11 +26,18 @@
Arm64LinkFlags = []string{}
Arm64ArchVariantRustFlags = map[string][]string{
- "armv8-a": []string{},
- "armv8-a-branchprot": []string{},
- "armv8-2a": []string{},
- "armv8-2a-dotprod": []string{},
- "armv9-a": []string{},
+ "armv8-a": []string{},
+ "armv8-a-branchprot": []string{
+ // branch-protection=bti,pac-ret is equivalent to Clang's mbranch-protection=standard
+ "-Z branch-protection=bti,pac-ret",
+ },
+ "armv8-2a": []string{},
+ "armv8-2a-dotprod": []string{},
+ "armv9-a": []string{
+ // branch-protection=bti,pac-ret is equivalent to Clang's mbranch-protection=standard
+ "-Z branch-protection=bti,pac-ret",
+ "-Z stack-protector=none",
+ },
}
)
diff --git a/rust/config/global.go b/rust/config/global.go
index d844a25..c39341e 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
var pctx = android.NewPackageContext("android/soong/rust/config")
var (
- RustDefaultVersion = "1.70.0"
+ RustDefaultVersion = "1.71.0"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2021"
Stdlibs = []string{
diff --git a/rust/image.go b/rust/image.go
index 53fb5c0..c2e250c 100644
--- a/rust/image.go
+++ b/rust/image.go
@@ -229,11 +229,6 @@
mctx.PropertyErrorf("vendor_ramdisk_available", "cannot be set for rust_ffi or rust_ffi_shared modules.")
}
}
- if mctx.ProductSpecific() {
- if lib, ok := mod.compiler.(libraryInterface); ok && lib.buildDylib() {
- mctx.PropertyErrorf("product", "Product-only dylibs are not yet supported, use rust_library_rlib.")
- }
- }
cc.MutateImage(mctx, mod)
diff --git a/rust/rust.go b/rust/rust.go
index 1b8ebd9..dab3532 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -43,6 +43,7 @@
android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel()
})
+ pctx.Import("android/soong/android")
pctx.Import("android/soong/rust/config")
pctx.ImportAs("cc_config", "android/soong/cc/config")
android.InitRegistrationContext.RegisterParallelSingletonType("kythe_rust_extract", kytheExtractRustFactory)
@@ -1305,12 +1306,17 @@
}
}
linkObject := ccDep.OutputFile()
- linkPath := linkPathFromFilePath(linkObject.Path())
-
if !linkObject.Valid() {
- ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
+ if !ctx.Config().AllowMissingDependencies() {
+ ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
+ } else {
+ ctx.AddMissingDependencies([]string{depName})
+ }
+ return
}
+ linkPath := linkPathFromFilePath(linkObject.Path())
+
exportDep := false
switch {
case cc.IsStaticDepTag(depTag):
@@ -1355,6 +1361,14 @@
// Re-get linkObject as ChooseStubOrImpl actually tells us which
// object (either from stub or non-stub) to use.
linkObject = android.OptionalPathForPath(sharedLibraryInfo.SharedLibrary)
+ if !linkObject.Valid() {
+ if !ctx.Config().AllowMissingDependencies() {
+ ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
+ } else {
+ ctx.AddMissingDependencies([]string{depName})
+ }
+ return
+ }
linkPath = linkPathFromFilePath(linkObject.Path())
depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
diff --git a/rust/sanitize.go b/rust/sanitize.go
index 0f7cf6e..862baf7 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -223,11 +223,16 @@
if !sanitize.Properties.SanitizerEnabled {
return flags, deps
}
+
if Bool(sanitize.Properties.Sanitize.Fuzzer) {
flags.RustFlags = append(flags.RustFlags, fuzzerFlags...)
- } else if Bool(sanitize.Properties.Sanitize.Hwaddress) {
+ }
+
+ if Bool(sanitize.Properties.Sanitize.Hwaddress) {
flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
- } else if Bool(sanitize.Properties.Sanitize.Address) {
+ }
+
+ if Bool(sanitize.Properties.Sanitize.Address) {
flags.RustFlags = append(flags.RustFlags, asanFlags...)
}
return flags, deps
@@ -267,14 +272,12 @@
var depTag blueprint.DependencyTag
var deps []string
- if mod.IsSanitizerEnabled(cc.Asan) ||
- (mod.IsSanitizerEnabled(cc.Fuzzer) && (mctx.Arch().ArchType != android.Arm64 || !mctx.Os().Bionic())) {
+ if mod.IsSanitizerEnabled(cc.Asan) {
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 && mctx.Os().Bionic()) {
+ } else if mod.IsSanitizerEnabled(cc.Hwasan) {
// 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/java_sdk_test.go b/sdk/java_sdk_test.go
index c018671..680494f 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -160,7 +160,7 @@
}
`),
checkAllCopyRules(`
-.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/myjavalib.jar
+.intermediates/myjavalib/linux_glibc_common/javac-header/myjavalib.jar -> java/myjavalib.jar
aidl/foo/bar/Test.aidl -> aidl/aidl/foo/bar/Test.aidl
`),
)
@@ -206,7 +206,7 @@
`),
checkAllCopyRules(`
.intermediates/myjavalib/android_common/turbine-combined/myjavalib.jar -> java/android/myjavalib.jar
-.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/linux_glibc/myjavalib.jar
+.intermediates/myjavalib/linux_glibc_common/javac-header/myjavalib.jar -> java/linux_glibc/myjavalib.jar
`),
)
}
@@ -799,7 +799,7 @@
libs: ["mysdk_system-module"],
}
`),
- checkAllCopyRules(".intermediates/system-module/linux_glibc_common/javac/system-module.jar -> java/system-module.jar"),
+ checkAllCopyRules(".intermediates/system-module/linux_glibc_common/javac-header/system-module.jar -> java/system-module.jar"),
)
}
@@ -879,7 +879,7 @@
}
`),
checkAllCopyRules(`
-.intermediates/hostjavalib/linux_glibc_common/javac/hostjavalib.jar -> java/hostjavalib.jar
+.intermediates/hostjavalib/linux_glibc_common/javac-header/hostjavalib.jar -> java/hostjavalib.jar
.intermediates/androidjavalib/android_common/turbine-combined/androidjavalib.jar -> java/androidjavalib.jar
.intermediates/myjavalib/android_common/javac/myjavalib.jar -> java/android/myjavalib.jar
.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/linux_glibc/myjavalib.jar
diff --git a/starlark_import/unmarshal.go b/starlark_import/unmarshal.go
index 1b54437..b243471 100644
--- a/starlark_import/unmarshal.go
+++ b/starlark_import/unmarshal.go
@@ -25,13 +25,18 @@
)
func Unmarshal[T any](value starlark.Value) (T, error) {
- var zero T
- x, err := UnmarshalReflect(value, reflect.TypeOf(zero))
+ x, err := UnmarshalReflect(value, reflect.TypeOf((*T)(nil)).Elem())
return x.Interface().(T), err
}
func UnmarshalReflect(value starlark.Value, ty reflect.Type) (reflect.Value, error) {
+ if ty == reflect.TypeOf((*starlark.Value)(nil)).Elem() {
+ return reflect.ValueOf(value), nil
+ }
zero := reflect.Zero(ty)
+ if value == nil {
+ panic("nil value")
+ }
var result reflect.Value
if ty.Kind() == reflect.Interface {
var err error
@@ -286,3 +291,14 @@
return nil, fmt.Errorf("unimplemented starlark type: %s", value.Type())
}
}
+
+// UnmarshalNoneable is like Unmarshal, but it will accept None as the top level (but not nested)
+// starlark value. If the value is None, a nil pointer will be returned, otherwise a pointer
+// to the result of Unmarshal will be returned.
+func UnmarshalNoneable[T any](value starlark.Value) (*T, error) {
+ if _, ok := value.(starlark.NoneType); ok {
+ return nil, nil
+ }
+ ret, err := Unmarshal[T](value)
+ return &ret, err
+}
diff --git a/starlark_import/unmarshal_test.go b/starlark_import/unmarshal_test.go
index ee7a9e3..bc0ea4c 100644
--- a/starlark_import/unmarshal_test.go
+++ b/starlark_import/unmarshal_test.go
@@ -30,7 +30,7 @@
return result["x"]
}
-func TestUnmarshallConcreteType(t *testing.T) {
+func TestUnmarshalConcreteType(t *testing.T) {
x, err := Unmarshal[string](createStarlarkValue(t, `"foo"`))
if err != nil {
t.Error(err)
@@ -41,7 +41,7 @@
}
}
-func TestUnmarshallConcreteTypeWithInterfaces(t *testing.T) {
+func TestUnmarshalConcreteTypeWithInterfaces(t *testing.T) {
x, err := Unmarshal[map[string]map[string]interface{}](createStarlarkValue(t,
`{"foo": {"foo2": "foo3"}, "bar": {"bar2": ["bar3"]}}`))
if err != nil {
@@ -57,7 +57,22 @@
}
}
-func TestUnmarshall(t *testing.T) {
+func TestUnmarshalToStarlarkValue(t *testing.T) {
+ x, err := Unmarshal[map[string]starlark.Value](createStarlarkValue(t,
+ `{"foo": "Hi", "bar": None}`))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if x["foo"].(starlark.String).GoString() != "Hi" {
+ t.Errorf("Expected \"Hi\", got: %q", x["foo"].(starlark.String).GoString())
+ }
+ if x["bar"].Type() != "NoneType" {
+ t.Errorf("Expected \"NoneType\", got: %q", x["bar"].Type())
+ }
+}
+
+func TestUnmarshal(t *testing.T) {
testCases := []struct {
input string
expected interface{}
diff --git a/tests/lib.sh b/tests/lib.sh
index 4aaf272..40b317b 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -147,6 +147,7 @@
symlink_directory external/bazelbuild-rules_go
symlink_directory external/bazelbuild-rules_license
symlink_directory external/bazelbuild-kotlin-rules
+ symlink_directory external/bazelbuild-rules_java
symlink_file WORKSPACE
symlink_file BUILD
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index 43a9f0f..6b9ff8b 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -10,7 +10,7 @@
"$TOP/build/soong/tests/persistent_bazel_test.sh"
"$TOP/build/soong/tests/soong_test.sh"
"$TOP/build/soong/tests/stale_metrics_files_test.sh"
-"$TOP/build/bazel/ci/rbc_regression_test.sh" aosp_arm64-userdebug
+"$TOP/prebuilts/build-tools/linux-x86/bin/py3-cmd" "$TOP/build/bazel/ci/rbc_dashboard.py" aosp_arm64-userdebug
# The following tests build against the full source tree and don't rely on the
# mock client.
@@ -22,7 +22,5 @@
"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_arm" "armv7-a"
"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_cf_arm64_phone" "armv8-a" "cortex-a53"
-"$TOP/build/soong/tests/sbom_test.sh"
-
"$TOP/build/bazel/ci/b_test.sh"
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
index 1241e89..2534b20 100755
--- a/tests/sbom_test.sh
+++ b/tests/sbom_test.sh
@@ -85,7 +85,13 @@
lz4=$out_dir/host/linux-x86/bin/lz4
declare -A diff_excludes
- diff_excludes[vendor]="-I /vendor/lib64/libkeystore2_crypto.so"
+ diff_excludes[product]="\
+ -I /product/etc/aconfig_flags.textproto \
+ -I /product/etc/build_flags.json"
+ diff_excludes[vendor]="\
+ -I /vendor/lib64/libkeystore2_crypto.so \
+ -I /vendor/etc/aconfig_flags.textproto \
+ -I /vendor/etc/build_flags.json"
diff_excludes[system]="\
-I /bin \
-I /bugreports \
@@ -105,6 +111,8 @@
-I /odm/priv-app \
-I /odm/usr \
-I /sdcard \
+ -I /system/etc/aconfig_flags.textproto \
+ -I /system/etc/build_flags.json \
-I /system/lib64/android.hardware.confirmationui@1.0.so \
-I /system/lib64/android.hardware.confirmationui-V1-ndk.so \
-I /system/lib64/android.hardware.keymaster@4.1.so \
@@ -134,6 +142,9 @@
-I /system/lib/vndk-sp-29 \
-I /system/usr/icu \
-I /vendor_dlkm/etc"
+ diff_excludes[system_ext]="\
+ -I /system_ext/etc/aconfig_flags.textproto \
+ -I /system_ext/etc/build_flags.json"
# Example output of dump.erofs is as below, and the data used in the test start
# at line 11. Column 1 is inode id, column 2 is inode type and column 3 is name.
@@ -227,10 +238,45 @@
diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name"
done
+ verify_package_verification_code "$product_out/sbom.spdx"
+
# Teardown
cleanup "${out_dir}"
}
+function verify_package_verification_code {
+ local sbom_file="$1"; shift
+
+ local -a file_checksums
+ local package_product_found=
+ while read -r line;
+ do
+ if grep -q 'PackageVerificationCode' <<<"$line"
+ then
+ package_product_found=true
+ fi
+ if [ -n "$package_product_found" ]
+ then
+ if grep -q 'FileChecksum' <<< "$line"
+ then
+ checksum=$(echo $line | sed 's/^.*: //')
+ file_checksums+=("$checksum")
+ fi
+ fi
+ done <<< "$(grep -E 'PackageVerificationCode|FileChecksum' $sbom_file)"
+ IFS=$'\n' file_checksums=($(sort <<<"${file_checksums[*]}")); unset IFS
+ IFS= expected_package_verification_code=$(printf "${file_checksums[*]}" | sha1sum | sed 's/[[:space:]]*-//'); unset IFS
+
+ actual_package_verification_code=$(grep PackageVerificationCode $sbom_file | sed 's/PackageVerificationCode: //g')
+ if [ $actual_package_verification_code = $expected_package_verification_code ]
+ then
+ echo "Package verification code is correct."
+ else
+ echo "Unexpected package verification code."
+ exit 1
+ fi
+}
+
function test_sbom_unbundled_apex {
# Setup
out_dir="$(setup)"
diff --git a/third_party/zip/android.go b/third_party/zip/android.go
index f8e45c5..0f41f62 100644
--- a/third_party/zip/android.go
+++ b/third_party/zip/android.go
@@ -170,7 +170,7 @@
func (w *Writer) CreateHeaderAndroid(fh *FileHeader) (io.Writer, error) {
writeDataDescriptor := fh.Method != Store
if writeDataDescriptor {
- fh.Flags &= DataDescriptorFlag
+ fh.Flags |= DataDescriptorFlag
} else {
fh.Flags &= ^uint16(DataDescriptorFlag)
}
diff --git a/ui/build/config.go b/ui/build/config.go
index fb5f7dd..e5c9a50 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -374,6 +374,11 @@
if err := loadEnvConfig(ctx, ret, bc); err != nil {
ctx.Fatalln("Failed to parse env config files: %v", err)
}
+ if !ret.canSupportRBE() {
+ // Explicitly set USE_RBE env variable to false when we cannot run
+ // an RBE build to avoid ninja local execution pool issues.
+ ret.environ.Set("USE_RBE", "false")
+ }
}
if distDir, ok := ret.environ.Get("DIST_DIR"); ok {
@@ -1374,18 +1379,26 @@
return true
}
+func (c *configImpl) canSupportRBE() bool {
+ // Do not use RBE with prod credentials in scenarios when stubby doesn't exist, since
+ // its unlikely that we will be able to obtain necessary creds without stubby.
+ authType, _ := c.rbeAuth()
+ if !c.StubbyExists() && strings.Contains(authType, "use_google_prod_creds") {
+ return false
+ }
+ return true
+}
+
func (c *configImpl) UseRBE() bool {
// These alternate modes of running Soong do not use RBE / reclient.
if c.Bp2Build() || c.Queryview() || c.ApiBp2build() || c.JsonModuleGraph() {
return false
}
- authType, _ := c.rbeAuth()
- // Do not use RBE with prod credentials in scenarios when stubby doesn't exist, since
- // its unlikely that we will be able to obtain necessary creds without stubby.
- if !c.StubbyExists() && strings.Contains(authType, "use_google_prod_creds") {
+ if !c.canSupportRBE() {
return false
}
+
if v, ok := c.Environment().Get("USE_RBE"); ok {
v = strings.TrimSpace(v)
if v != "" && v != "false" {
diff --git a/zip/cmd/BUILD.bazel b/zip/cmd/BUILD.bazel
deleted file mode 100644
index e04a1e1..0000000
--- a/zip/cmd/BUILD.bazel
+++ /dev/null
@@ -1,20 +0,0 @@
-# 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.
-
-# TODO(b/194644518): Switch to the source version when Bazel can build go
-# binaries.
-alias(
- name = "soong_zip",
- actual = "//prebuilts/build-tools:linux-x86/bin/soong_zip",
-)