diff options
86 files changed, 2876 insertions, 492 deletions
diff --git a/aconfig/Android.bp b/aconfig/Android.bp index ae8276f39..6927765a8 100644 --- a/aconfig/Android.bp +++ b/aconfig/Android.bp @@ -20,6 +20,7 @@ bootstrap_go_package { "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 @@ bootstrap_go_package { "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/cc_aconfig_library.go b/aconfig/cc_aconfig_library.go new file mode 100644 index 000000000..14090bc90 --- /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 634612d63..37167aa5d 100644 --- a/aconfig/init.go +++ b/aconfig/init.go @@ -30,7 +30,7 @@ var ( ` ${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}", @@ -39,11 +39,12 @@ var ( }, "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 @@ var ( "$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 @@ func registerBuildComponents(ctx android.RegistrationContext) { 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 0eeb14ffc..53f8bd1ba 100644 --- a/aconfig/java_aconfig_library.go +++ b/aconfig/java_aconfig_library.go @@ -30,6 +30,9 @@ var declarationsTag = declarationsTagType{} 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) DepsMutator(module *ja } } -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 @@ func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuild } 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 000000000..af50848f1 --- /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 d121b1375..ecd8bd769 100644 --- a/android/allowlists/allowlists.go +++ b/android/allowlists/allowlists.go @@ -142,11 +142,12 @@ var ( "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, @@ -229,6 +230,7 @@ var ( "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, @@ -476,6 +478,8 @@ var ( Bp2buildModuleAlwaysConvertList = []string{ "libidmap2_policies", "libSurfaceFlingerProp", + "toolbox_input_labels", + // cc mainline modules // com.android.media.swcodec @@ -493,7 +497,6 @@ var ( "code_coverage.policy.other", "codec2_soft_exports", "compatibility_matrix_schema", - "flatbuffer_headers", "framework-connectivity-protos", "gemmlowp_headers", "gl_headers", @@ -616,10 +619,6 @@ var ( "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", @@ -677,6 +676,7 @@ var ( "libcodec2_hidl@1.2", "libcodec2_hidl_plugin_stub", "libcodec2_hidl_plugin", + "libcodec2_hal_common", "libstagefright_bufferqueue_helper_novndk", "libGLESv2", "libEGL", @@ -766,6 +766,7 @@ var ( // Mainline Module Apps "CaptivePortalLogin", + "ModuleMetadata", "libstagefright_headers", @@ -808,6 +809,12 @@ var ( "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", } Bp2buildModuleTypeAlwaysConvertList = []string{ @@ -912,7 +919,10 @@ var ( "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 @@ -1494,8 +1504,6 @@ var ( "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 @@ -1599,6 +1607,11 @@ var ( "test_com.android.neuralnetworks", "libneuralnetworks", "libneuralnetworks_static", + // M13: media.swcodec launch + "com.android.media.swcodec", + "test_com.android.media.swcodec", + "libstagefright_foundation", + "libcodec2_hidl@1.0", } // Staging-mode allowlist. Modules in this list are only built @@ -1606,13 +1619,7 @@ var ( // which will soon be added to the prod allowlist. // It is implicit that all modules in ProdMixedBuildsEnabledList will // also be built - do not add them to this list. - StagingMixedBuildsEnabledList = []string{ - // M13: media.swcodec launch - "com.android.media.swcodec", - "test_com.android.media.swcodec", - "libstagefright_foundation", - "libcodec2_hidl@1.0", - } + StagingMixedBuildsEnabledList = []string{} // These should be the libs that are included by the apexes in the ProdMixedBuildsEnabledList ProdDclaMixedBuildsEnabledList = []string{ @@ -1620,14 +1627,13 @@ var ( "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", diff --git a/android/api_levels.go b/android/api_levels.go index 2391e6cc2..44c86403d 100644 --- a/android/api_levels.go +++ b/android/api_levels.go @@ -275,10 +275,6 @@ var FirstAndroidRelrVersion = uncheckedFinalApiLevel(28) // 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 4d91cc839..94bc88b42 100644 --- a/android/bazel_handler.go +++ b/android/bazel_handler.go @@ -1389,9 +1389,6 @@ func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath)) } } - for _, inputPath := range buildStatement.OrderOnlyInputs { - cmd.OrderOnly(PathForBazelOut(ctx, inputPath)) - } for _, inputPath := range buildStatement.InputPaths { cmd.Implicit(PathForBazelOut(ctx, inputPath)) } diff --git a/android/bazel_paths.go b/android/bazel_paths.go index 8956a18d5..756854315 100644 --- a/android/bazel_paths.go +++ b/android/bazel_paths.go @@ -124,6 +124,7 @@ func BazelLabelForModuleDepsWithFn(ctx BazelConversionPathContext, modules []str labels.Includes = []bazel.Label{} return labels } + modules = FirstUniqueStrings(modules) for _, module := range modules { bpText := module if m := SrcIsModule(module); m == "" { diff --git a/android/config.go b/android/config.go index 2a243eeb9..72ff2247a 100644 --- a/android/config.go +++ b/android/config.go @@ -170,6 +170,19 @@ func (c Config) RunningInsideUnitTest() bool { 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). @@ -1909,6 +1922,10 @@ func (c *deviceConfig) RequiresInsecureExecmemForSwiftshader() bool { 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/module.go b/android/module.go index 384776a65..4c781f6fe 100644 --- a/android/module.go +++ b/android/module.go @@ -4029,43 +4029,26 @@ type XsdConfigBp2buildTargets interface { 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/variable.go b/android/variable.go index 1c81f3c3d..7fb81b905 100644 --- a/android/variable.go +++ b/android/variable.go @@ -95,6 +95,10 @@ type variableProperties struct { Cflags []string } + Device_page_size_agnostic struct { + Cflags []string `android:"arch_variant"` + } `android:"arch_variant"` + Override_rs_driver struct { Cflags []string } @@ -180,6 +184,13 @@ type variableProperties struct { 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"` } @@ -275,6 +286,7 @@ type ProductVariables struct { 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 @@ type ProductVariables struct { SelinuxIgnoreNeverallows bool `json:",omitempty"` + Release_aidl_use_unfrozen *bool `json:",omitempty"` + SepolicyFreezeTestExtraDirs []string `json:",omitempty"` SepolicyFreezeTestExtraPrebuiltDirs []string `json:",omitempty"` @@ -529,6 +543,7 @@ func (v *ProductVariables) SetDefaultConfig() { 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{}}, @@ -728,7 +743,9 @@ func (p *ProductConfigProperties) AddEitherProperty( 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 @@ -941,7 +958,7 @@ func (productConfigProperties *ProductConfigProperties) AddSoongConfigProperties 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 1d094eb31..b26d1d242 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -993,7 +993,7 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) { // 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 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, // 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 @@ func makeApexAvailableBaseline() map[string][]string { // 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 @@ func makeApexAvailableBaseline() map[string][]string { "libprocinfo", "libpropertyinfoparser", "libscudo", - "libstdc++", "libsystemproperties", "libtombstoned_client_static", "libunwindstack", @@ -3742,3 +3716,12 @@ func invalidCompileMultilib(ctx android.TopDownMutatorContext, value string) { 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 df138e054..9dba08e46 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -3029,7 +3029,11 @@ func TestVendorApex_use_vndk_as_stable(t *testing.T) { 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 @@ func TestApexAvailable_ApexAvailableNameWithVersionCode(t *testing.T) { 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 @@ func TestApexAvailable_ApexAvailableNameWithVersionCode(t *testing.T) { 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 186a4945b..2c080a11a 100644 --- a/bazel/aquery.go +++ b/bazel/aquery.go @@ -115,7 +115,6 @@ type BuildStatement struct { // input path string, but not both. InputDepsetHashes []string InputPaths []string - OrderOnlyInputs []string FileContents string // If ShouldRunInSbox is true, Soong will use sbox to created an isolated environment // and run the mixed build action there @@ -138,8 +137,6 @@ type aqueryArtifactHandler struct { depsetHashToArtifactPathsCache sync.Map // Maps artifact ids to fully expanded paths. artifactIdToPath map[artifactId]string - - extraBuildStatements []*BuildStatement } // The tokens should be substituted with the value specified here, instead of the @@ -169,29 +166,13 @@ func newAqueryHandler(aqueryResult *analysis_v2_proto.ActionGraphContainer) (*aq return pathFragmentId(pf.Id) }) - var extraBuildStatements []*BuildStatement artifactIdToPath := make(map[artifactId]string, len(aqueryResult.Artifacts)) for _, artifact := range aqueryResult.Artifacts { artifactPath, err := expandPathFragment(pathFragmentId(artifact.PathFragmentId), pathFragments) if err != nil { return nil, err } - if strings.HasSuffix(artifactPath, "DumpPlatformClassPath.java") { - // TODO(b/291828210): This is a workaround for the fact that DumpPlatformClassPath.java - // has a timestamp in 2033. We'll copy it to a new file using a order-only dep, so that - // the file is not recopied every build. Technically the order-only dep would produce - // incremental build issues if this was a regular file produced as part of the build, - // but this file is actually created by bazel during analysis, so it's not an issue. - outputPath := "hack_for_b291828210/DumpPlatformClassPath.java" - extraBuildStatements = append(extraBuildStatements, &BuildStatement{ - Command: fmt.Sprintf("cp %s %s", artifactPath, outputPath), - OutputPaths: []string{outputPath}, - OrderOnlyInputs: []string{artifactPath}, - }) - artifactIdToPath[artifactId(artifact.Id)] = outputPath - } else { - artifactIdToPath[artifactId(artifact.Id)] = artifactPath - } + artifactIdToPath[artifactId(artifact.Id)] = artifactPath } // Map middleman artifact ContentHash to input artifact depset ID. @@ -218,7 +199,6 @@ func newAqueryHandler(aqueryResult *analysis_v2_proto.ActionGraphContainer) (*aq depsetHashToArtifactPathsCache: sync.Map{}, emptyDepsetIds: make(map[depsetId]struct{}, 0), artifactIdToPath: artifactIdToPath, - extraBuildStatements: extraBuildStatements, } // Validate and adjust aqueryResult.DepSetOfFiles values. @@ -392,7 +372,6 @@ func AqueryBuildStatements(aqueryJsonProto []byte, eventHandler *metrics.EventHa if err != nil { return nil, nil, err } - buildStatements = append(buildStatements, aqueryHandler.extraBuildStatements...) depsetsByHash := map[string]AqueryDepset{} depsets := make([]AqueryDepset, 0, len(aqueryHandler.depsetIdToAqueryDepset)) @@ -480,7 +459,7 @@ func (a *aqueryArtifactHandler) depsetContentHashes(inputDepsetIds []uint32) ([] // 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 == "" { diff --git a/bazel/properties.go b/bazel/properties.go index 15af09b45..702c31c4d 100644 --- a/bazel/properties.go +++ b/bazel/properties.go @@ -288,6 +288,41 @@ func SubtractBazelLabelList(haystack LabelList, needle LabelList) LabelList { 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 c56d11f3f..c98ae0ea2 100644 --- a/bazel/properties_test.go +++ b/bazel/properties_test.go @@ -125,6 +125,63 @@ func TestSubtractBazelLabelList(t *testing.T) { } } } + +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 TestFirstUniqueBazelLabelList(t *testing.T) { } } +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 f889693c4..4a3786feb 100644 --- a/bp2build/Android.bp +++ b/bp2build/Android.bp @@ -46,6 +46,7 @@ bootstrap_go_package { "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_product_config.go b/bp2build/bp2build_product_config.go index 42a086695..f56e6d86e 100644 --- a/bp2build/bp2build_product_config.go +++ b/bp2build/bp2build_product_config.go @@ -7,6 +7,7 @@ import ( "fmt" "os" "path/filepath" + "reflect" "strings" "github.com/google/blueprint/proptools" @@ -151,16 +152,17 @@ func platformMappingContent(mainProductLabel string, mainProductVariables *andro if err != nil { return "", err } - result := "platforms:\n" - result += platformMappingSingleProduct(mainProductLabel, mainProductVariables) + 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 } - result += platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables) + platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables, &result) } - return result, nil + return result.String(), nil } var bazelPlatformSuffixes = []string{ @@ -177,37 +179,107 @@ var bazelPlatformSuffixes = []string{ "_windows_x86_64", } -func platformMappingSingleProduct(label string, productVariables *android.ProductVariables) string { - buildSettings := "" - buildSettings += fmt.Sprintf(" --//build/bazel/product_config:apex_global_min_sdk_version_override=%s\n", proptools.String(productVariables.ApexGlobalMinSdkVersionOverride)) - buildSettings += fmt.Sprintf(" --//build/bazel/product_config:cfi_include_paths=%s\n", strings.Join(productVariables.CFIIncludePaths, ",")) - buildSettings += fmt.Sprintf(" --//build/bazel/product_config:cfi_exclude_paths=%s\n", strings.Join(productVariables.CFIExcludePaths, ",")) - buildSettings += fmt.Sprintf(" --//build/bazel/product_config:enable_cfi=%t\n", proptools.BoolDefault(productVariables.EnableCFI, true)) - result := "" +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 += " " + label + suffix + "\n" + buildSettings + 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, ","))) } - return result } func starlarkMapToProductVariables(in map[string]starlark.Value) (android.ProductVariables, error) { - var err error result := android.ProductVariables{} - result.ApexGlobalMinSdkVersionOverride, err = starlark_import.UnmarshalNoneable[string](in["ApexGlobalMinSdkVersionOverride"]) - if err != nil { - return result, err - } - result.CFIIncludePaths, err = starlark_import.Unmarshal[[]string](in["CFIIncludePaths"]) - if err != nil { - return result, err - } - result.CFIExcludePaths, err = starlark_import.Unmarshal[[]string](in["CFIExcludePaths"]) - if err != nil { - return result, err - } - result.EnableCFI, err = starlark_import.UnmarshalNoneable[bool](in["EnableCFI"]) - if err != nil { - return result, err + 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 000000000..3dd53ce23 --- /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 0e6596bf7..3de5213b3 100644 --- a/bp2build/build_conversion.go +++ b/bp2build/build_conversion.go @@ -353,7 +353,104 @@ type goAttributes struct { 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 @@ func generateBazelTargetsGoPackage(ctx *android.Context, g *bootstrap.GoPackage, 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 @@ func generateBazelTargetsGoBinary(ctx *android.Context, g *bootstrap.GoBinary, g 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 @@ func generateBazelTargetsGoBinary(ctx *android.Context, g *bootstrap.GoBinary, g // 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,12 +642,14 @@ func generateBazelTargetsGoBinary(ctx *android.Context, g *bootstrap.GoBinary, g 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} + + if binTarget, err := generateBazelTarget(ctx, bin); err == nil { + retTargets = append(retTargets, binTarget) + } else { + retErrs = []error{err} } - return []BazelTarget{binTarget}, nil + + return retTargets, retErrs } func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (conversionResults, []error) { diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go index 8084a5d8e..03e9cd060 100644 --- a/bp2build/cc_library_static_conversion_test.go +++ b/bp2build/cc_library_static_conversion_test.go @@ -1003,6 +1003,38 @@ cc_library_static { }) } +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 4df4d4d46..3c037b494 100644 --- a/bp2build/cc_test_conversion_test.go +++ b/bp2build/cc_test_conversion_test.go @@ -94,7 +94,9 @@ cc_test_library { 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_test_library { ":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 @@ cc_test_library { "//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 @@ cc_test { targets: []testBazelTarget{ {"cc_test", "mytest", AttrNameToString{ "gtest": "False", - "isolated": "False", "local_includes": `["."]`, "srcs": `["test.cpp"]`, }, @@ -171,14 +174,17 @@ cc_test { 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 @@ cc_test { 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 @@ cc_test { 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 @@ cc_test { 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 @@ cc_test { ]`, "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 5cf4fb216..5a739699a 100644 --- a/bp2build/genrule_conversion_test.go +++ b/bp2build/genrule_conversion_test.go @@ -16,6 +16,7 @@ package bp2build import ( "fmt" + "path/filepath" "testing" "android/soong/android" @@ -695,3 +696,79 @@ func TestCcGenruleArchAndExcludeSrcs(t *testing.T) { }) }) } + +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 507fbf0ae..2387641f2 100644 --- a/bp2build/go_conversion_test.go +++ b/bp2build/go_conversion_test.go @@ -45,11 +45,17 @@ bootstrap_go_package { 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 @@ bootstrap_go_package { })`, }, 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 @@ bootstrap_go_package { }) } +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 f411ffb07..f41345e87 100644 --- a/bp2build/java_test_host_conversion_test.go +++ b/bp2build/java_test_host_conversion_test.go @@ -71,6 +71,11 @@ java_library { }), 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 @@ java_test_host { `, 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 813773d00..143597d2b 100644 --- a/bp2build/soong_config_module_type_conversion_test.go +++ b/bp2build/soong_config_module_type_conversion_test.go @@ -1406,3 +1406,111 @@ cc_binary { 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 f49dc1a9e..e88ea03b3 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -32,6 +32,7 @@ bootstrap_go_package { "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 bc7cd5212..23d196dba 100644 --- a/cc/afdo.go +++ b/cc/afdo.go @@ -131,6 +131,10 @@ func (c *Module) fdoProfileMutator(ctx android.BottomUpMutatorContext) { 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 a5571f31f..69a0d3ae4 100644 --- a/cc/api_level.go +++ b/cc/api_level.go @@ -31,7 +31,11 @@ func MinApiForArch(ctx android.EarlyModuleContext, 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 6e00aa828..9e485d6d0 100644 --- a/cc/bp2build.go +++ b/cc/bp2build.go @@ -22,6 +22,7 @@ import ( "android/soong/android" "android/soong/bazel" "android/soong/cc/config" + "android/soong/genrule" "github.com/google/blueprint" @@ -43,6 +44,12 @@ const ( rScriptSrcPartition = "renderScript" + xsdSrcPartition = "xsd" + + genrulePartition = "genrule" + + hdrPartition = "hdr" + stubsSuffix = "_stub_libs_current" ) @@ -155,6 +162,7 @@ func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.Lab 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 @@ func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.Lab 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 @@ type compilerAttributes struct { 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 parseCommandLineFlags(soongFlags []string, filterOut ...filterOutFn) []stri 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) convertProductVariables(ctx android.BazelConversio } } -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 @@ func (ca *compilerAttributes) finalize(ctx android.BazelConversionPathContext, i 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 @@ func (ca *compilerAttributes) finalize(ctx android.BazelConversionPathContext, i } // 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 @@ func parseSrcs(ctx android.BazelConversionPathContext, props *BaseCompilerProper 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 @@ func packageFromLabel(label string) (string, bool) { 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 @@ func includesFromLabelList(labelList bazel.LabelList) (relative, absolute []stri 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 @@ func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) 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 @@ func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) 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 @@ func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) 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 @@ func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) 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 @@ func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) } } - 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 @@ func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) (&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 @@ -1748,16 +1800,8 @@ func bazelLabelForStaticWholeModuleDeps(ctx android.BazelConversionPathContext, 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 { @@ -569,6 +569,24 @@ type feature interface { 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 { @@ -851,6 +869,7 @@ type Module struct { // 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 @@ -1201,6 +1220,9 @@ func (c *Module) VndkVersion() string { 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()...) } @@ -2149,6 +2171,25 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { 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()) @@ -2163,6 +2204,9 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { 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) } @@ -2220,6 +2264,10 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { 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) @@ -2307,6 +2355,9 @@ func (c *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain { } func (c *Module) begin(ctx BaseModuleContext) { + for _, generator := range c.generators { + generator.GeneratorInit(ctx) + } if c.compiler != nil { c.compiler.compilerInit(ctx) } @@ -2342,6 +2393,9 @@ func (c *Module) begin(ctx BaseModuleContext) { 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) } diff --git a/cc/cc_test.go b/cc/cc_test.go index 7534db222..d95ed3f3e 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -3261,7 +3261,7 @@ func TestLibDepAndroidMkExportInMixedBuilds(t *testing.T) { }, }, 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 16f4a6ec0..5bed8a72f 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -189,13 +189,13 @@ type BaseCompilerProperties struct { // 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 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps 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 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps 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 266d2789b..ff5ab051e 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -149,6 +149,7 @@ var ( commonGlobalLldflags = []string{ "-fuse-ld=lld", "-Wl,--icf=safe", + "-Wl,--no-demangle", } deviceGlobalCppflags = []string{ diff --git a/cc/config/vndk.go b/cc/config/vndk.go index dd612ce63..f9b3eac82 100644 --- a/cc/config/vndk.go +++ b/cc/config/vndk.go @@ -21,6 +21,7 @@ package config var VndkMustUseVendorVariantList = []string{ "android.hardware.nfc@1.2", "libbinder", + "libdumpstateutil", "libcrypto", "libexpat", "libgatekeeper", diff --git a/cc/coverage.go b/cc/coverage.go index c0f697398..cbd8a6f3e 100644 --- a/cc/coverage.go +++ b/cc/coverage.go @@ -48,6 +48,7 @@ func (cov *coverage) props() []interface{} { 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 @@ func getClangProfileLibraryName(ctx ModuleContextIntf) string { } else { return "libprofile-clang-extras" } + // LINT.ThenChange(library.go) } func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps { diff --git a/cc/generated_cc_library.go b/cc/generated_cc_library.go new file mode 100644 index 000000000..55e19f9a9 --- /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 e65a9aadb..f91762adc 100644 --- a/cc/image.go +++ b/cc/image.go @@ -678,10 +678,17 @@ func squashVendorRamdiskSrcs(m *Module) { } } +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 266fa7511..df1dbc5b4 100644 --- a/cc/library.go +++ b/cc/library.go @@ -32,6 +32,20 @@ import ( "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 @@ func libraryBp2Build(ctx android.TopDownMutatorContext, m *Module) { 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) @@ -2951,6 +2969,10 @@ func sharedOrStaticLibraryBp2Build(ctx android.TopDownMutatorContext, module *Mo 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 @@ func sharedOrStaticLibraryBp2Build(ctx android.TopDownMutatorContext, module *Mo Conlyflags: compilerAttrs.conlyFlags, Asflags: asFlags, - Features: *features, + Alwayslink: alwayslink, + Features: *features, } + } else { commonAttrs.Dynamic_deps.Add(baseAttributes.protoDependency) @@ -3047,7 +3071,8 @@ type bazelCcLibraryStaticAttributes struct { 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? @@ -101,11 +101,12 @@ func rsGenerateCpp(ctx android.ModuleContext, rsFiles android.Paths, rsFlags str 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 626005b44..c1ef97034 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -56,10 +56,6 @@ var ( // 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", } @@ -80,8 +80,7 @@ func (stl *stl) begin(ctx BaseModuleContext) { 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 (stl *stl) begin(ctx BaseModuleContext) { }() } -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 @@ func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps { } 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 3f5f71007..0be230151 100644 --- a/cc/test.go +++ b/cc/test.go @@ -267,7 +267,7 @@ func (test *testDecorator) gtest() bool { 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 @@ type ccTestBazelHandler struct { 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 @@ func (handler *ccTestBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleC type testBinaryAttributes struct { binaryAttributes - Gtest bool - Isolated bool + Gtest *bool tidyAttributes tradefed.TestConfigAttributes @@ -708,13 +720,15 @@ func testBinaryBp2build(ctx android.TopDownMutatorContext, m *Module) { 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 @@ func testBinaryBp2build(ctx android.TopDownMutatorContext, m *Module) { 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 @@ func testBinaryBp2build(ctx android.TopDownMutatorContext, m *Module) { }, &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 d346739bd..d1632aaa6 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -423,11 +423,6 @@ func commonDefaultModules() string { 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 @@ var PrepareForTestWithCcDefaultModules = android.GroupFixturePreparers( // 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/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go index e3d1179b4..a70a9d158 100644 --- a/cmd/merge_zips/merge_zips.go +++ b/cmd/merge_zips/merge_zips.go @@ -122,7 +122,7 @@ func (be ZipEntryFromBuffer) Size() uint64 { } 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 @@ func mergeZips(inputZips []InputZip, writer *zip.Writer, manifest, pyMain string } } + var jarServices jar.Services + // Finally, add entries from all the input zips. for _, inputZip := range inputZips { _, copyFully := zipsToNotStrip[inputZip.Name()] @@ -570,6 +572,14 @@ func mergeZips(inputZips []InputZip, writer *zip.Writer, manifest, pyMain string } 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 @@ func mergeZips(inputZips []InputZip, writer *zip.Writer, manifest, pyMain string } 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 cb5843607..767d4e61f 100644 --- a/cmd/merge_zips/merge_zips_test.go +++ b/cmd/merge_zips/merge_zips_test.go @@ -17,6 +17,7 @@ package main import ( "bytes" "fmt" + "hash/crc32" "os" "strconv" "strings" @@ -27,28 +28,34 @@ import ( ) 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("")} - - 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")} + 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} + + 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 @@ func TestMergeZips(t *testing.T) { "in1": true, }, }, + { + name: "services", + in: [][]testZipEntry{ + {service1a, service2}, + {service1b}, + }, + jar: true, + out: []testZipEntry{service1combined, service2}, + }, } for _, test := range testCases { @@ -256,7 +272,7 @@ func TestMergeZips(t *testing.T) { closeErr := writer.Close() if closeErr != nil { - t.Fatal(err) + t.Fatal(closeErr) } if test.err != "" { @@ -266,12 +282,16 @@ func TestMergeZips(t *testing.T) { 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 @@ func testZipEntriesToBuf(entries []testZipEntry) []byte { 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/genrule/allowlists.go b/genrule/allowlists.go index c6fa03039..afa52cc7b 100644 --- a/genrule/allowlists.go +++ b/genrule/allowlists.go @@ -116,6 +116,25 @@ var ( "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 a470c5e8a..69ba1e94e 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -296,6 +296,9 @@ func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) { 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 @@ func (m *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m) + bazelName := m.Name() if ctx.ModuleType() == "gensrcs" { props := bazel.BazelTargetModuleProperties{ Rule_class: "gensrcs", @@ -1018,7 +1022,6 @@ func (m *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { 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 @@ func (m *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { 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 @@ func getSandboxingAllowlistSets(ctx android.PathContext) *sandboxingAllowlistSet } }).(*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 6301bbf01..7c14531bd 100644 --- a/genrule/genrule_test.go +++ b/genrule/genrule_test.go @@ -845,6 +845,49 @@ func TestGenruleOutputFiles(t *testing.T) { 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 46113d877..c03e49174 100644 --- a/jar/Android.bp +++ b/jar/Android.bp @@ -21,6 +21,7 @@ bootstrap_go_package { 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 000000000..d06a6dc99 --- /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 c9e08e2b5..180e1d726 100644 --- a/java/aar.go +++ b/java/aar.go @@ -88,28 +88,40 @@ type aaptProperties struct { // 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 propagateRROEnforcementMutator(ctx android.TopDownMutatorContext) { } } +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 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkConte // 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 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon 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 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon 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 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon // 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 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon 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 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon 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 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon 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()) @@ -613,9 +729,12 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) a.stem = proptools.StringDefault(a.overridableDeviceProperties.Stem, ctx.ModuleName()) - ctx.CheckbuildFile(a.proguardOptionsFile) - ctx.CheckbuildFile(a.exportPackage) - ctx.CheckbuildFile(a.aaptSrcJar) + 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 @@ -627,7 +746,22 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) 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 @@ -729,12 +863,15 @@ type AARImport struct { 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] @@ -903,12 +1040,13 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { 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(), @@ -928,14 +1066,14 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { // 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", } @@ -948,25 +1086,35 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { _ = 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() @@ -981,6 +1129,8 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { _ = staticManifestsDepSet a.manifestsDepSet = manifestDepSetBuilder.Build() + a.transitiveAaptResourcePackages = staticDeps.resPackages() + a.collectTransitiveHeaderJars(ctx) ctx.SetProvider(JavaInfoProvider, JavaInfo{ HeaderJars: android.PathsIfNonNil(a.classpathFile), @@ -988,6 +1138,7 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { 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 784fa29b5..82505e9e3 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -123,6 +123,8 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { 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 @@ func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries { 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 @@ func (prebuilt *DexImport) AndroidMkEntries() []android.AndroidMkEntries { 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 @@ func (prebuilt *AARImport) AndroidMkEntries() []android.AndroidMkEntries { 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 @@ func (binary *Binary) AndroidMkEntries() []android.AndroidMkEntries { 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 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { // 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 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { } 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{ @@ -508,10 +522,12 @@ func (a *AndroidLibrary) AndroidMkEntries() []android.AndroidMkEntries { } 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 @@ -684,6 +700,7 @@ func (a *AndroidAppImport) AndroidMkEntries() []android.AndroidMkEntries { if Bool(a.properties.Export_package_resources) { entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.outputFile) } + // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts }, }, }} @@ -717,6 +734,7 @@ func (r *RuntimeResourceOverlay) AndroidMkEntries() []android.AndroidMkEntries { 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? }, }, }} @@ -734,6 +752,7 @@ func (apkSet *AndroidAppSet) AndroidMkEntries() []android.AndroidMkEntries { 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 8e4efd2b2..224bc8867 100755 --- a/java/app.go +++ b/java/app.go @@ -521,7 +521,23 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { 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() diff --git a/java/app_builder.go b/java/app_builder.go index d20a6bfe4..d397ff7f5 100644 --- a/java/app_builder.go +++ b/java/app_builder.go @@ -225,8 +225,6 @@ func BuildBundleModule(ctx android.ModuleContext, outputFile android.WritablePat }) } -const jniJarOutputPathString = "jniJarOutput.zip" - func TransformJniLibsToJar( ctx android.ModuleContext, outputFile android.WritablePath, @@ -258,7 +256,10 @@ func TransformJniLibsToJar( 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 @@ func TransformJniLibsToJar( 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 e25bcd1b7..ad1765e9d 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -51,9 +51,9 @@ var ( 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 @@ var ( "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) generateAndroidBuildActions(ctx android.ModuleContext } 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 c438b6cfa..8474ea7d6 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -722,7 +722,10 @@ func TestAppJavaResources(t *testing.T) { 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 @@ func TestAndroidResourceProcessor(t *testing.T) { 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 @@ func TestAndroidResourceProcessor(t *testing.T) { "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 @@ func TestAndroidResourceProcessor(t *testing.T) { "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 @@ func TestAndroidResourceProcessor(t *testing.T) { 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", + }, + }, + { + // 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", }, - transitiveImportImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"}, + + 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 @@ func TestAndroidResourceProcessor(t *testing.T) { resource_dirs: ["app/res"], manifest: "app/AndroidManifest.xml", static_libs: ["direct", "direct_import"], + use_resource_processor: %v, } android_library { @@ -848,6 +1093,7 @@ func TestAndroidResourceProcessor(t *testing.T) { resource_dirs: ["direct/res"], manifest: "direct/AndroidManifest.xml", static_libs: ["transitive", "transitive_import"], + use_resource_processor: %v, } android_library { @@ -856,6 +1102,7 @@ func TestAndroidResourceProcessor(t *testing.T) { srcs: ["transitive/transitive.java"], resource_dirs: ["transitive/res"], manifest: "transitive/AndroidManifest.xml", + use_resource_processor: %v, } android_library_import { @@ -883,7 +1130,7 @@ func TestAndroidResourceProcessor(t *testing.T) { 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 @@ func TestJNIABI(t *testing.T) { 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 @@ func TestJNIPackaging(t *testing.T) { 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 @@ func TestJNISDK(t *testing.T) { 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 @@ func TestStl(t *testing.T) { 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 8db716256..f5eb01c4b 100644 --- a/java/base.go +++ b/java/base.go @@ -508,6 +508,14 @@ type Module struct { // 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 { @@ -1057,7 +1065,7 @@ func (module *Module) addGeneratedSrcJars(path android.Path) { 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) @@ -1095,9 +1103,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { 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") @@ -1140,6 +1146,11 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { 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 @@ -1233,8 +1244,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // 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 } @@ -1385,6 +1397,8 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { 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 @@ -1477,7 +1491,13 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { 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) @@ -1623,6 +1643,8 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { ctx.CheckbuildFile(outputFile) + j.collectTransitiveAconfigFiles(ctx) + ctx.SetProvider(JavaInfoProvider, JavaInfo{ HeaderJars: android.PathsIfNonNil(j.headerJarFile), TransitiveLibsHeaderJars: j.transitiveLibsHeaderJars, @@ -1637,6 +1659,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { 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 @@ -1917,6 +1940,34 @@ func (j *Module) IsInstallable() bool { 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 be4af552b..debf49a00 100644 --- a/java/builder.go +++ b/java/builder.go @@ -42,7 +42,7 @@ var ( // 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 @@ var ( `$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 @@ var ( "$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 @@ var ( 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 TransformJarsToJar(ctx android.ModuleContext, outputFile android.WritablePa }) } +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 195dae16b..83c27d309 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -148,6 +148,8 @@ func init() { 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 eadd9c697..de9a82d09 100644 --- a/java/core-libraries/Android.bp +++ b/java/core-libraries/Android.bp @@ -146,12 +146,43 @@ java_system_modules { ], } +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 @@ java_library { "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 @@ java_library { 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 0cf0f360b..c46f8b8ea 100644 --- a/java/core-libraries/TxtStubLibraries.bp +++ b/java/core-libraries/TxtStubLibraries.bp @@ -57,19 +57,23 @@ java_library { ], } -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", + ], + libs: [ + "stub-annotations", ], - sdk_version: "none", - system_modules: "none", visibility: ["//visibility:private"], } diff --git a/java/device_host_converter.go b/java/device_host_converter.go index 3581040f8..5460dc993 100644 --- a/java/device_host_converter.go +++ b/java/device_host_converter.go @@ -143,6 +143,8 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont 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 3c9a0f3f1..3413da03d 100644 --- a/java/device_host_converter_test.go +++ b/java/device_host_converter_test.go @@ -135,6 +135,7 @@ func TestHostForDevice(t *testing.T) { 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 @@ func TestHostForDevice(t *testing.T) { // 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 dd1e96b3e..f29c91327 100644 --- a/java/fuzz_test.go +++ b/java/fuzz_test.go @@ -71,8 +71,8 @@ func TestJavaFuzz(t *testing.T) { } 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 1b3de9fe0..f9baa85e4 100644 --- a/java/generated_java_library.go +++ b/java/generated_java_library.go @@ -30,7 +30,7 @@ type GeneratedJavaLibraryCallbacks interface { // 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 @@ func (module *GeneratedJavaLibraryModule) GenerateAndroidBuildActions(ctx androi 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 68f1f7edd..7f52fd108 100644 --- a/java/generated_java_library_test.go +++ b/java/generated_java_library_test.go @@ -36,7 +36,8 @@ type JavaGenLibTestCallbacks struct { 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 d25096b15..4d08b8307 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -106,7 +106,7 @@ func (h *hiddenAPI) initHiddenAPI(ctx android.ModuleContext, dexJar OptionalDexJ 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 714634f58..8ec17971a 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -121,8 +121,8 @@ type hiddenAPISingleton struct { // 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 6388d13e3..f29f7383a 100644 --- a/java/java.go +++ b/java/java.go @@ -274,7 +274,14 @@ type JavaInfo struct { // 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{}) @@ -692,7 +699,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { 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()) @@ -730,6 +737,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { } }) j.exportedProguardFlagFiles = android.FirstUniquePaths(j.exportedProguardFlagFiles) + } func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) { @@ -1916,6 +1924,7 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { ImplementationAndResourcesJars: android.PathsIfNonNil(al.stubsJar), ImplementationJars: android.PathsIfNonNil(al.stubsJar), AidlIncludeDirs: android.Paths{}, + // No aconfig libraries on api libraries }) } @@ -2237,6 +2246,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedClasspathFile), ImplementationJars: android.PathsIfNonNil(j.combinedClasspathFile), AidlIncludeDirs: j.exportAidlIncludeDirs, + // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts }) } @@ -2809,12 +2819,8 @@ type bp2BuildJavaInfo struct { 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 @@ -2825,21 +2831,14 @@ func xsdConfigJavaTarget(ctx android.BazelConversionPathContext, mod blueprint.M 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) - } } } @@ -2847,6 +2846,7 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) javaSrcPartition := "java" protoSrcPartition := "proto" + xsdSrcPartition := "xsd" logtagSrcPartition := "logtag" aidlSrcPartition := "aidl" kotlinPartition := "kotlin" @@ -2855,6 +2855,7 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) 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"}}, }) @@ -2862,6 +2863,8 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) kotlinSrcs := srcPartitions[kotlinPartition] javaSrcs.Append(kotlinSrcs) + staticDeps.Append(srcPartitions[xsdSrcPartition]) + if !srcPartitions[logtagSrcPartition].IsEmpty() { logtagsLibName := m.Name() + "_logtags" ctx.CreateBazelTargetModule( @@ -2915,7 +2918,7 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) }, ) - staticDeps.Add(&bazel.Label{Label: ":" + javaAidlLibName}) + staticDeps.Append(bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + javaAidlLibName})) } var javacopts bazel.StringListAttribute //[]string @@ -2970,7 +2973,9 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) // 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 @@ -2985,7 +2990,7 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) } } } - depLabels.StaticDeps.Value.Append(staticDeps) + depLabels.StaticDeps.Append(staticDeps) hasKotlin := !kotlinSrcs.IsEmpty() commonAttrs.kotlinAttributes = &kotlinAttributes{ @@ -3155,6 +3160,7 @@ func javaBinaryHostBp2Build(ctx android.TopDownMutatorContext, m *Binary) { type javaTestHostAttributes struct { *javaCommonAttributes + Srcs bazel.LabelListAttribute Deps bazel.LabelListAttribute Runtime_deps bazel.LabelListAttribute } @@ -3191,8 +3197,10 @@ func javaTestHostBp2Build(ctx android.TopDownMutatorContext, m *TestHost) { 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) } @@ -3305,7 +3313,8 @@ func (i *Import) ProcessBazelQueryResponse(ctx android.ModuleContext) { 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/kotlin.go b/java/kotlin.go index f28d6c737..3637e2e71 100644 --- a/java/kotlin.go +++ b/java/kotlin.go @@ -42,7 +42,7 @@ var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports ` -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 a4bba486d..ade739552 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -113,7 +113,7 @@ func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorCon } func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpMutatorContext) { - if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { + if ctx.Config().DisableHiddenApiChecks() { return } @@ -275,10 +275,10 @@ func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android. 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/rust/bindgen.go b/rust/bindgen.go index 59585aaf8..c2bf6af4c 100644 --- a/rust/bindgen.go +++ b/rust/bindgen.go @@ -61,15 +61,18 @@ var ( "${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 @@ type BindgenProperties struct { // 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 @@ func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) andr 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 @@ func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) andr 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 af04cfc89..12cdb3cb4 100644 --- a/rust/bindgen_test.go +++ b/rust/bindgen_test.go @@ -168,3 +168,28 @@ func TestBindgenDisallowedFlags(t *testing.T) { } `) } + +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 c31bc88d1..fbceecc80 100644 --- a/rust/builder.go +++ b/rust/builder.go @@ -228,6 +228,17 @@ func rustEnvVars(ctx ModuleContext, deps PathDeps) []string { 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 ae783e8dd..08ac2ef7d 100644 --- a/rust/config/arm64_device.go +++ b/rust/config/arm64_device.go @@ -26,11 +26,18 @@ var ( 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 d844a252b..c39341e4c 100644 --- a/rust/config/global.go +++ b/rust/config/global.go @@ -24,7 +24,7 @@ import ( var pctx = android.NewPackageContext("android/soong/rust/config") var ( - RustDefaultVersion = "1.70.0" + RustDefaultVersion = "1.71.0" RustDefaultBase = "prebuilts/rust/" DefaultEdition = "2021" Stdlibs = []string{ diff --git a/rust/image.go b/rust/image.go index 53fb5c023..c2e250cf0 100644 --- a/rust/image.go +++ b/rust/image.go @@ -229,11 +229,6 @@ func (mod *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { 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 05fceee36..dab35323a 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -1306,12 +1306,17 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } } 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): @@ -1356,6 +1361,14 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // 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 0f7cf6e5f..862baf7cc 100644 --- a/rust/sanitize.go +++ b/rust/sanitize.go @@ -223,11 +223,16 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags, deps PathDeps) ( 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 @@ func rustSanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { 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 c018671ee..680494f3a 100644 --- a/sdk/java_sdk_test.go +++ b/sdk/java_sdk_test.go @@ -160,7 +160,7 @@ java_import { } `), 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 @@ java_import { `), 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 @@ java_system_modules_import { 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 @@ java_import { } `), 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 33c0cd92b..b2434712b 100644 --- a/starlark_import/unmarshal.go +++ b/starlark_import/unmarshal.go @@ -34,6 +34,9 @@ func UnmarshalReflect(value starlark.Value, ty reflect.Type) (reflect.Value, err 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 diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh index 1241e899c..afec6b1ce 100755 --- a/tests/sbom_test.sh +++ b/tests/sbom_test.sh @@ -85,7 +85,13 @@ function test_sbom_aosp_cf_x86_64_phone { 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 @@ function test_sbom_aosp_cf_x86_64_phone { -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 @@ function test_sbom_aosp_cf_x86_64_phone { -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. diff --git a/third_party/zip/android.go b/third_party/zip/android.go index f8e45c56d..0f41f6200 100644 --- a/third_party/zip/android.go +++ b/third_party/zip/android.go @@ -170,7 +170,7 @@ func (w *Writer) CreateCompressedHeader(fh *FileHeader) (io.WriteCloser, error) 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 fb5f7dd58..e5c9a5012 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -374,6 +374,11 @@ func NewConfig(ctx Context, args ...string) Config { 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 @@ func (c *configImpl) StartGoma() bool { 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" { |