diff options
140 files changed, 4998 insertions, 1846 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/aconfig_declarations.go b/aconfig/aconfig_declarations.go index 007d5290f..565d18534 100644 --- a/aconfig/aconfig_declarations.go +++ b/aconfig/aconfig_declarations.go @@ -125,12 +125,12 @@ func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.Module intermediatePath := android.PathForModuleOut(ctx, "intermediate.pb") ctx.Build(pctx, android.BuildParams{ Rule: aconfigRule, - Inputs: inputFiles, Output: intermediatePath, Description: "aconfig_declarations", Args: map[string]string{ "release_version": ctx.Config().ReleaseVersion(), "package": module.properties.Package, + "declarations": android.JoinPathsWithPrefix(inputFiles, "--declarations "), "values": joinAndPrefix(" --values ", module.properties.Values), }, }) diff --git a/aconfig/aconfig_declarations_test.go b/aconfig/aconfig_declarations_test.go index e14ca3851..e0d8f7d5a 100644 --- a/aconfig/aconfig_declarations_test.go +++ b/aconfig/aconfig_declarations_test.go @@ -26,7 +26,10 @@ func TestAconfigDeclarations(t *testing.T) { aconfig_declarations { name: "module_name", package: "com.example.package", - srcs: ["foo.aconfig"], + srcs: [ + "foo.aconfig", + "bar.aconfig", + ], } ` result := runTest(t, android.FixtureExpectsNoErrors, bp) diff --git a/aconfig/cc_aconfig_library.go b/aconfig/cc_aconfig_library.go new file mode 100644 index 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 161fd4248..3ed5faf6a 100644 --- a/aconfig/init.go +++ b/aconfig/init.go @@ -27,7 +27,7 @@ var ( blueprint.RuleParams{ Command: `${aconfig} create-cache` + ` --package ${package}` + - ` --declarations ${in}` + + ` ${declarations}` + ` ${values}` + ` --cache ${out}.tmp` + ` && ( if cmp -s ${out}.tmp ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`, @@ -36,10 +36,10 @@ var ( "${aconfig}", }, Restat: true, - }, "release_version", "package", "values") + }, "release_version", "package", "declarations", "values") // For java_aconfig_library: Generate java file - srcJarRule = pctx.AndroidStaticRule("aconfig_srcjar", + javaRule = pctx.AndroidStaticRule("java_aconfig_library", blueprint.RuleParams{ Command: `rm -rf ${out}.tmp` + ` && mkdir -p ${out}.tmp` + @@ -55,6 +55,20 @@ var ( Restat: true, }) + // 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", blueprint.RuleParams{ @@ -75,6 +89,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..53b2b10cf 100644 --- a/aconfig/java_aconfig_library.go +++ b/aconfig/java_aconfig_library.go @@ -51,7 +51,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 +59,18 @@ 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") ctx.Build(pctx, android.BuildParams{ - Rule: srcJarRule, + Rule: javaRule, Input: declarations.IntermediatePath, Output: srcJarPath, Description: "aconfig.srcjar", }) + // 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..1808290ee --- /dev/null +++ b/aconfig/java_aconfig_library_test.go @@ -0,0 +1,154 @@ +// 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 ( + "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) +} diff --git a/android/Android.bp b/android/Android.bp index fc5198fee..f5bb785ff 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -107,6 +107,7 @@ bootstrap_go_package { "bazel_test.go", "config_test.go", "config_bp2build_test.go", + "configured_jars_test.go", "csuite_config_test.go", "defaults_test.go", "depset_test.go", diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go index d320599e1..69bcd2e4b 100644 --- a/android/allowlists/allowlists.go +++ b/android/allowlists/allowlists.go @@ -141,11 +141,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, @@ -227,6 +228,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, @@ -429,6 +431,7 @@ var ( // external/bazelbuild-rules_android/... is needed by mixed builds, otherwise mixed builds analysis fails // e.g. ERROR: Analysis of target '@soong_injection//mixed_builds:buildroot' failed "external/bazelbuild-rules_android":/* recursive = */ true, + "external/bazelbuild-rules_java":/* recursive = */ true, "external/bazelbuild-rules_license":/* recursive = */ true, "external/bazelbuild-rules_go":/* recursive = */ true, "external/bazelbuild-kotlin-rules":/* recursive = */ true, @@ -473,6 +476,8 @@ var ( Bp2buildModuleAlwaysConvertList = []string{ "libidmap2_policies", "libSurfaceFlingerProp", + "toolbox_input_labels", + // cc mainline modules // com.android.media.swcodec @@ -490,7 +495,6 @@ var ( "code_coverage.policy.other", "codec2_soft_exports", "compatibility_matrix_schema", - "flatbuffer_headers", "framework-connectivity-protos", "gemmlowp_headers", "gl_headers", @@ -613,10 +617,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", @@ -674,6 +674,7 @@ var ( "libcodec2_hidl@1.2", "libcodec2_hidl_plugin_stub", "libcodec2_hidl_plugin", + "libcodec2_hal_common", "libstagefright_bufferqueue_helper_novndk", "libGLESv2", "libEGL", @@ -763,6 +764,7 @@ var ( // Mainline Module Apps "CaptivePortalLogin", + "ModuleMetadata", "libstagefright_headers", @@ -805,6 +807,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{ @@ -909,7 +917,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 @@ -931,9 +942,6 @@ var ( "test_fips", // depends on unconverted modules: adb "timezone-host", // depends on unconverted modules: art.module.api.annotations - // '//bionic/libc:libc_bp2build_cc_library_static' is duplicated in the 'deps' attribute of rule - "toybox-static", - // aidl files not created "overlayable_policy_aidl_interface", @@ -1016,6 +1024,7 @@ var ( "bionic-unit-tests-static", "boringssl_crypto_test", "boringssl_ssl_test", + "boringssl_test_support", //b/244431896 "cfi_test_helper", "cfi_test_helper2", "cintltst32", @@ -1493,8 +1502,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 @@ -1598,6 +1605,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 @@ -1605,13 +1617,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{ @@ -1619,14 +1625,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.go b/android/bazel.go index 1bfbdec00..0d2c7776f 100644 --- a/android/bazel.go +++ b/android/bazel.go @@ -255,7 +255,7 @@ func (b *BazelModuleBase) GetBazelLabel(ctx BazelConversionPathContext, module b if b.ShouldConvertWithBp2build(ctx) { return bp2buildModuleLabel(ctx, module) } - panic(fmt.Errorf("requested non-existent label for module ", module.Name())) + panic(fmt.Errorf("requested non-existent label for module %s", module.Name())) } type Bp2BuildConversionAllowlist struct { diff --git a/android/bazel_handler.go b/android/bazel_handler.go index 5d93f06b8..94bc88b42 100644 --- a/android/bazel_handler.go +++ b/android/bazel_handler.go @@ -16,6 +16,8 @@ package android import ( "bytes" + "crypto/sha1" + "encoding/hex" "fmt" "os" "path" @@ -1222,7 +1224,11 @@ func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) { ctx.AddNinjaFileDeps(file) } + depsetHashToDepset := map[string]bazel.AqueryDepset{} + for _, depset := range ctx.Config().BazelContext.AqueryDepsets() { + depsetHashToDepset[depset.ContentHash] = depset + var outputs []Path var orderOnlies []Path for _, depsetDepHash := range depset.TransitiveDepSetHashes { @@ -1257,7 +1263,30 @@ func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) { } if len(buildStatement.Command) > 0 { rule := NewRuleBuilder(pctx, ctx) - createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx) + intermediateDir, intermediateDirHash := intermediatePathForSboxMixedBuildAction(ctx, buildStatement) + if buildStatement.ShouldRunInSbox { + // Create a rule to build the output inside a sandbox + // This will create two changes of working directory + // 1. From ANDROID_BUILD_TOP to sbox top + // 2. From sbox top to a a synthetic mixed build execution root relative to it + // Finally, the outputs will be copied to intermediateDir + rule.Sbox(intermediateDir, + PathForOutput(ctx, "mixed_build_sbox_intermediates", intermediateDirHash+".textproto")). + SandboxInputs(). + // Since we will cd to mixed build execution root, set sbox's out subdir to empty + // Without this, we will try to copy from $SBOX_SANDBOX_DIR/out/out/bazel/output/execroot/__main__/... + SetSboxOutDirDirAsEmpty() + + // Create another set of rules to copy files from the intermediate dir to mixed build execution root + for _, outputPath := range buildStatement.OutputPaths { + ctx.Build(pctx, BuildParams{ + Rule: CpIfChanged, + Input: intermediateDir.Join(ctx, executionRoot, outputPath), + Output: PathForBazelOut(ctx, outputPath), + }) + } + } + createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx, depsetHashToDepset) desc := fmt.Sprintf("%s: %s", buildStatement.Mnemonic, buildStatement.OutputPaths) rule.Build(fmt.Sprintf("bazel %d", index), desc) continue @@ -1304,10 +1333,25 @@ func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) { } } +// Returns a out dir path for a sandboxed mixed build action +func intermediatePathForSboxMixedBuildAction(ctx PathContext, statement *bazel.BuildStatement) (OutputPath, string) { + // An artifact can be generated by a single buildstatement. + // Use the hash of the first artifact to create a unique path + uniqueDir := sha1.New() + uniqueDir.Write([]byte(statement.OutputPaths[0])) + uniqueDirHashString := hex.EncodeToString(uniqueDir.Sum(nil)) + return PathForOutput(ctx, "mixed_build_sbox_intermediates", uniqueDirHashString), uniqueDirHashString +} + // Register bazel-owned build statements (obtained from the aquery invocation). -func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx BuilderContext) { +func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx BuilderContext, depsetHashToDepset map[string]bazel.AqueryDepset) { // executionRoot is the action cwd. - cmd.Text(fmt.Sprintf("cd '%s' &&", executionRoot)) + if buildStatement.ShouldRunInSbox { + // mkdir -p ensures that the directory exists when run via sbox + cmd.Text(fmt.Sprintf("mkdir -p '%s' && cd '%s' &&", executionRoot, executionRoot)) + } else { + cmd.Text(fmt.Sprintf("cd '%s' &&", executionRoot)) + } // Remove old outputs, as some actions might not rerun if the outputs are detected. if len(buildStatement.OutputPaths) > 0 { @@ -1334,14 +1378,30 @@ func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement } for _, outputPath := range buildStatement.OutputPaths { - cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath)) + if buildStatement.ShouldRunInSbox { + // The full path has three components that get joined together + // 1. intermediate output dir that `sbox` will place the artifacts at + // 2. mixed build execution root + // 3. artifact path returned by aquery + intermediateDir, _ := intermediatePathForSboxMixedBuildAction(ctx, buildStatement) + cmd.ImplicitOutput(intermediateDir.Join(ctx, executionRoot, outputPath)) + } else { + cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath)) + } } for _, inputPath := range buildStatement.InputPaths { cmd.Implicit(PathForBazelOut(ctx, inputPath)) } for _, inputDepsetHash := range buildStatement.InputDepsetHashes { - otherDepsetName := bazelDepsetName(inputDepsetHash) - cmd.Implicit(PathForPhony(ctx, otherDepsetName)) + if buildStatement.ShouldRunInSbox { + // Bazel depsets are phony targets that are used to group files. + // We need to copy the grouped files into the sandbox + ds, _ := depsetHashToDepset[inputDepsetHash] + cmd.Implicits(PathsForBazelOut(ctx, ds.DirectArtifacts)) + } else { + otherDepsetName := bazelDepsetName(inputDepsetHash) + cmd.Implicit(PathForPhony(ctx, otherDepsetName)) + } } if depfile := buildStatement.Depfile; depfile != nil { diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go index 65cd5a836..e08a4718a 100644 --- a/android/bazel_handler_test.go +++ b/android/bazel_handler_test.go @@ -181,13 +181,62 @@ func TestInvokeBazelPopulatesBuildStatements(t *testing.T) { cmd := RuleBuilderCommand{} ctx := builderContextForTests{PathContextForTesting(TestConfig("out", nil, "", nil))} - createCommand(&cmd, got[0], "test/exec_root", "test/bazel_out", ctx) + createCommand(&cmd, got[0], "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{}) if actual, expected := cmd.buf.String(), testCase.command; expected != actual { t.Errorf("expected: [%s], actual: [%s]", expected, actual) } } } +func TestMixedBuildSandboxedAction(t *testing.T) { + input := `{ + "artifacts": [ + { "id": 1, "path_fragment_id": 1 }, + { "id": 2, "path_fragment_id": 2 }], + "actions": [{ + "target_Id": 1, + "action_Key": "x", + "mnemonic": "x", + "arguments": ["touch", "foo"], + "input_dep_set_ids": [1], + "output_Ids": [1], + "primary_output_id": 1 + }], + "dep_set_of_files": [ + { "id": 1, "direct_artifact_ids": [1, 2] }], + "path_fragments": [ + { "id": 1, "label": "one" }, + { "id": 2, "label": "two" }] +}` + data, err := JsonToActionGraphContainer(input) + if err != nil { + t.Error(err) + } + bazelContext, _ := testBazelContext(t, map[bazelCommand]string{aqueryCmd: string(data)}) + + err = bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{}) + if err != nil { + t.Fatalf("TestMixedBuildSandboxedAction did not expect error invoking Bazel, but got %s", err) + } + + statement := bazelContext.BuildStatementsToRegister()[0] + statement.ShouldRunInSbox = true + + cmd := RuleBuilderCommand{} + ctx := builderContextForTests{PathContextForTesting(TestConfig("out", nil, "", nil))} + createCommand(&cmd, statement, "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{}) + // Assert that the output is generated in an intermediate directory + // fe05bcdcdc4928012781a5f1a2a77cbb5398e106 is the sha1 checksum of "one" + if actual, expected := cmd.outputs[0].String(), "out/soong/mixed_build_sbox_intermediates/fe05bcdcdc4928012781a5f1a2a77cbb5398e106/test/exec_root/one"; expected != actual { + t.Errorf("expected: [%s], actual: [%s]", expected, actual) + } + + // Assert the actual command remains unchanged inside the sandbox + if actual, expected := cmd.buf.String(), "mkdir -p 'test/exec_root' && cd 'test/exec_root' && rm -rf 'one' && touch foo"; expected != actual { + t.Errorf("expected: [%s], actual: [%s]", expected, actual) + } +} + func TestCoverageFlagsAfterInvokeBazel(t *testing.T) { testConfig.productVariables.ClangCoverage = boolPtr(true) diff --git a/android/bazel_paths.go b/android/bazel_paths.go index 872e908e8..8956a18d5 100644 --- a/android/bazel_paths.go +++ b/android/bazel_paths.go @@ -179,7 +179,7 @@ func BazelLabelForModuleDepSingle(ctx BazelConversionPathContext, path string) b // paths, relative to the local module, or Bazel-labels (absolute if in a different package or // relative if within the same package). // Properties must have been annotated with struct tag `android:"path"` so that dependencies modules -// will have already been handled by the path_deps mutator. +// will have already been handled by the pathdeps mutator. func BazelLabelForModuleSrc(ctx BazelConversionPathContext, paths []string) bazel.LabelList { return BazelLabelForModuleSrcExcludes(ctx, paths, []string(nil)) } @@ -189,7 +189,7 @@ func BazelLabelForModuleSrc(ctx BazelConversionPathContext, paths []string) baze // references in paths, minus those in excludes, relative to the local module, or Bazel-labels // (absolute if in a different package or relative if within the same package). // Properties must have been annotated with struct tag `android:"path"` so that dependencies modules -// will have already been handled by the path_deps mutator. +// will have already been handled by the pathdeps mutator. func BazelLabelForModuleSrcExcludes(ctx BazelConversionPathContext, paths, excludes []string) bazel.LabelList { excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil)) excluded := make([]string, 0, len(excludeLabels.Includes)) @@ -198,7 +198,7 @@ func BazelLabelForModuleSrcExcludes(ctx BazelConversionPathContext, paths, exclu } labels := expandSrcsForBazel(ctx, paths, excluded) labels.Excludes = excludeLabels.Includes - labels = transformSubpackagePaths(ctx, labels) + labels = TransformSubpackagePaths(ctx.Config(), ctx.ModuleDir(), labels) return labels } @@ -237,7 +237,7 @@ func isPackageBoundary(config Config, prefix string, components []string, compon // if the "async_safe" directory is actually a package and not just a directory. // // In particular, paths that extend into packages are transformed into absolute labels beginning with //. -func transformSubpackagePath(ctx BazelConversionPathContext, path bazel.Label) bazel.Label { +func transformSubpackagePath(cfg Config, dir string, path bazel.Label) bazel.Label { var newPath bazel.Label // Don't transform OriginalModuleName @@ -281,7 +281,7 @@ func transformSubpackagePath(ctx BazelConversionPathContext, path bazel.Label) b for i := len(pathComponents) - 1; i >= 0; i-- { pathComponent := pathComponents[i] var sep string - if !foundPackageBoundary && isPackageBoundary(ctx.Config(), ctx.ModuleDir(), pathComponents, i) { + if !foundPackageBoundary && isPackageBoundary(cfg, dir, pathComponents, i) { sep = ":" foundPackageBoundary = true } else { @@ -295,7 +295,7 @@ func transformSubpackagePath(ctx BazelConversionPathContext, path bazel.Label) b } if foundPackageBoundary { // Ensure paths end up looking like //bionic/... instead of //./bionic/... - moduleDir := ctx.ModuleDir() + moduleDir := dir if strings.HasPrefix(moduleDir, ".") { moduleDir = moduleDir[1:] } @@ -313,13 +313,13 @@ func transformSubpackagePath(ctx BazelConversionPathContext, path bazel.Label) b // Transform paths to acknowledge package boundaries // See transformSubpackagePath() for more information -func transformSubpackagePaths(ctx BazelConversionPathContext, paths bazel.LabelList) bazel.LabelList { +func TransformSubpackagePaths(cfg Config, dir string, paths bazel.LabelList) bazel.LabelList { var newPaths bazel.LabelList for _, include := range paths.Includes { - newPaths.Includes = append(newPaths.Includes, transformSubpackagePath(ctx, include)) + newPaths.Includes = append(newPaths.Includes, transformSubpackagePath(cfg, dir, include)) } for _, exclude := range paths.Excludes { - newPaths.Excludes = append(newPaths.Excludes, transformSubpackagePath(ctx, exclude)) + newPaths.Excludes = append(newPaths.Excludes, transformSubpackagePath(cfg, dir, exclude)) } return newPaths } @@ -355,7 +355,7 @@ func RootToModuleRelativePaths(ctx BazelConversionPathContext, paths Paths) []ba // // Properties passed as the paths or excludes argument must have been annotated with struct tag // `android:"path"` so that dependencies on other modules will have already been handled by the -// path_deps mutator. +// pathdeps mutator. func expandSrcsForBazel(ctx BazelConversionPathContext, paths, expandedExcludes []string) bazel.LabelList { if paths == nil { return bazel.LabelList{} diff --git a/android/bazel_paths_test.go b/android/bazel_paths_test.go index 450bf7674..60c0a1478 100644 --- a/android/bazel_paths_test.go +++ b/android/bazel_paths_test.go @@ -175,7 +175,7 @@ func TestTransformSubpackagePath(t *testing.T) { "./z/b.c": "z/b.c", } for in, out := range pairs { - actual := transformSubpackagePath(ctx, bazel.Label{Label: in}).Label + actual := transformSubpackagePath(ctx.Config(), ctx.ModuleDir(), bazel.Label{Label: in}).Label if actual != out { t.Errorf("expected:\n%v\nactual:\n%v", out, actual) } diff --git a/android/config.go b/android/config.go index fa439625d..30be7d60b 100644 --- a/android/config.go +++ b/android/config.go @@ -18,7 +18,6 @@ package android // product variables necessary for soong_build's operation. import ( - "bytes" "encoding/json" "fmt" "os" @@ -202,10 +201,10 @@ type VendorConfig soongconfig.SoongConfig // product configuration values are read from Kati-generated soong.variables. type config struct { // Options configurable with soong.variables - productVariables productVariables + productVariables ProductVariables // Only available on configs created by TestConfig - TestProductVariables *productVariables + TestProductVariables *ProductVariables // A specialized context object for Bazel/Soong mixed builds and migration // purposes. @@ -321,7 +320,7 @@ func loadConfig(config *config) error { // loadFromConfigFile loads and decodes configuration options from a JSON file // in the current working directory. -func loadFromConfigFile(configurable *productVariables, filename string) error { +func loadFromConfigFile(configurable *ProductVariables, filename string) error { // Try to open the file configFileReader, err := os.Open(filename) defer configFileReader.Close() @@ -373,7 +372,7 @@ func loadFromConfigFile(configurable *productVariables, filename string) error { // atomically writes the config file in case two copies of soong_build are running simultaneously // (for example, docs generation and ninja manifest generation) -func saveToConfigFile(config *productVariables, filename string) error { +func saveToConfigFile(config *ProductVariables, filename string) error { data, err := json.MarshalIndent(&config, "", " ") if err != nil { return fmt.Errorf("cannot marshal config data: %s", err.Error()) @@ -402,7 +401,7 @@ func saveToConfigFile(config *productVariables, filename string) error { return nil } -func saveToBazelConfigFile(config *productVariables, outDir string) error { +func saveToBazelConfigFile(config *ProductVariables, outDir string) error { dir := filepath.Join(outDir, bazel.SoongInjectionDirName, "product_config") err := createDirIfNonexistent(dir, os.ModePerm) if err != nil { @@ -431,32 +430,6 @@ func saveToBazelConfigFile(config *productVariables, outDir string) error { return fmt.Errorf("cannot marshal arch variant product variable data: %s", err.Error()) } - configJson, err := json.MarshalIndent(&config, "", " ") - if err != nil { - return fmt.Errorf("cannot marshal config data: %s", err.Error()) - } - // The backslashes need to be escaped because this text is going to be put - // inside a Starlark string literal. - configJson = bytes.ReplaceAll(configJson, []byte("\\"), []byte("\\\\")) - - bzl := []string{ - bazel.GeneratedBazelFileWarning, - fmt.Sprintf(`_product_vars = json.decode("""%s""")`, configJson), - fmt.Sprintf(`_product_var_constraints = %s`, nonArchVariantProductVariablesJson), - fmt.Sprintf(`_arch_variant_product_var_constraints = %s`, archVariantProductVariablesJson), - "\n", ` -product_vars = _product_vars - -# TODO(b/269577299) Remove these when everything switches over to loading them from product_variable_constants.bzl -product_var_constraints = _product_var_constraints -arch_variant_product_var_constraints = _arch_variant_product_var_constraints -`, - } - err = pathtools.WriteFileIfChanged(filepath.Join(dir, "product_variables.bzl"), - []byte(strings.Join(bzl, "\n")), 0644) - if err != nil { - return fmt.Errorf("Could not write .bzl config file %s", err) - } err = pathtools.WriteFileIfChanged(filepath.Join(dir, "product_variable_constants.bzl"), []byte(fmt.Sprintf(` product_var_constraints = %s arch_variant_product_var_constraints = %s @@ -1355,6 +1328,10 @@ func (c *config) BazelModulesForceEnabledByFlag() map[string]struct{} { return c.bazelForceEnabledModules } +func (c *config) IsVndkDeprecated() bool { + return !Bool(c.productVariables.KeepVndk) +} + func (c *deviceConfig) Arches() []Arch { var arches []Arch for _, target := range c.config.Targets[Android] { @@ -1932,6 +1909,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/config_test.go b/android/config_test.go index 9df5288a1..7d327a27e 100644 --- a/android/config_test.go +++ b/android/config_test.go @@ -75,7 +75,7 @@ Did you mean to use an annotation of ",omitempty"? // run validateConfigAnnotations against each type that might have json annotations func TestProductConfigAnnotations(t *testing.T) { - err := validateConfigAnnotations(&productVariables{}) + err := validateConfigAnnotations(&ProductVariables{}) if err != nil { t.Errorf(err.Error()) } @@ -88,7 +88,7 @@ func TestMissingVendorConfig(t *testing.T) { } } -func verifyProductVariableMarshaling(t *testing.T, v productVariables) { +func verifyProductVariableMarshaling(t *testing.T, v ProductVariables) { dir := t.TempDir() path := filepath.Join(dir, "test.variables") err := saveToConfigFile(&v, path) @@ -96,20 +96,20 @@ func verifyProductVariableMarshaling(t *testing.T, v productVariables) { t.Errorf("Couldn't save default product config: %q", err) } - var v2 productVariables + var v2 ProductVariables err = loadFromConfigFile(&v2, path) if err != nil { t.Errorf("Couldn't load default product config: %q", err) } } func TestDefaultProductVariableMarshaling(t *testing.T) { - v := productVariables{} + v := ProductVariables{} v.SetDefaultConfig() verifyProductVariableMarshaling(t, v) } func TestBootJarsMarshaling(t *testing.T) { - v := productVariables{} + v := ProductVariables{} v.SetDefaultConfig() v.BootJars = ConfiguredJarList{ apexes: []string{"apex"}, diff --git a/android/configured_jars.go b/android/configured_jars.go index 53fef052a..c7b808f3d 100644 --- a/android/configured_jars.go +++ b/android/configured_jars.go @@ -178,7 +178,7 @@ func (l *ConfiguredJarList) CopyOfApexJarPairs() []string { func (l *ConfiguredJarList) BuildPaths(ctx PathContext, dir OutputPath) WritablePaths { paths := make(WritablePaths, l.Len()) for i, jar := range l.jars { - paths[i] = dir.Join(ctx, ModuleStem(jar)+".jar") + paths[i] = dir.Join(ctx, ModuleStem(ctx.Config(), l.Apex(i), jar)+".jar") } return paths } @@ -187,8 +187,8 @@ func (l *ConfiguredJarList) BuildPaths(ctx PathContext, dir OutputPath) Writable // prefix. func (l *ConfiguredJarList) BuildPathsByModule(ctx PathContext, dir OutputPath) map[string]WritablePath { paths := map[string]WritablePath{} - for _, jar := range l.jars { - paths[jar] = dir.Join(ctx, ModuleStem(jar)+".jar") + for i, jar := range l.jars { + paths[jar] = dir.Join(ctx, ModuleStem(ctx.Config(), l.Apex(i), jar)+".jar") } return paths } @@ -228,24 +228,32 @@ func (l *ConfiguredJarList) MarshalJSON() ([]byte, error) { return json.Marshal(list) } -// ModuleStem hardcodes the stem of framework-minus-apex to return "framework". -// -// TODO(b/139391334): hard coded until we find a good way to query the stem of a -// module before any other mutators are run. -func ModuleStem(module string) string { - if module == "framework-minus-apex" { - return "framework" +func OverrideConfiguredJarLocationFor(cfg Config, apex string, jar string) (newApex string, newJar string) { + for _, entry := range cfg.productVariables.ConfiguredJarLocationOverrides { + tuple := strings.Split(entry, ":") + if len(tuple) != 4 { + panic("malformed configured jar location override '%s', expected format: <old_apex>:<old_jar>:<new_apex>:<new_jar>") + } + if apex == tuple[0] && jar == tuple[1] { + return tuple[2], tuple[3] + } } - return module + return apex, jar +} + +// ModuleStem returns the overridden jar name. +func ModuleStem(cfg Config, apex string, jar string) string { + _, newJar := OverrideConfiguredJarLocationFor(cfg, apex, jar) + return newJar } // DevicePaths computes the on-device paths for the list of (apex, jar) pairs, // based on the operating system. func (l *ConfiguredJarList) DevicePaths(cfg Config, ostype OsType) []string { paths := make([]string, l.Len()) - for i, jar := range l.jars { - apex := l.apexes[i] - name := ModuleStem(jar) + ".jar" + for i := 0; i < l.Len(); i++ { + apex, jar := OverrideConfiguredJarLocationFor(cfg, l.Apex(i), l.Jar(i)) + name := jar + ".jar" var subdir string if apex == "platform" { @@ -311,4 +319,9 @@ func EmptyConfiguredJarList() ConfiguredJarList { return ConfiguredJarList{} } +// IsConfiguredJarForPlatform returns true if the given apex name is a special name for the platform. +func IsConfiguredJarForPlatform(apex string) bool { + return apex == "platform" || apex == "system_ext" +} + var earlyBootJarsKey = NewOnceKey("earlyBootJars") diff --git a/android/configured_jars_test.go b/android/configured_jars_test.go new file mode 100644 index 000000000..4b586e4d7 --- /dev/null +++ b/android/configured_jars_test.go @@ -0,0 +1,46 @@ +// 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 android + +import ( + "testing" +) + +func TestOverrideConfiguredJarLocationFor(t *testing.T) { + cfg := NullConfig("", "") + + cfg.productVariables = ProductVariables{ + ConfiguredJarLocationOverrides: []string{ + "platform:libfoo-old:com.android.foo:libfoo-new", + "com.android.bar:libbar-old:platform:libbar-new", + }, + } + + apex, jar := OverrideConfiguredJarLocationFor(cfg, "platform", "libfoo-old") + AssertStringEquals(t, "", "com.android.foo", apex) + AssertStringEquals(t, "", "libfoo-new", jar) + + apex, jar = OverrideConfiguredJarLocationFor(cfg, "platform", "libbar-old") + AssertStringEquals(t, "", "platform", apex) + AssertStringEquals(t, "", "libbar-old", jar) + + apex, jar = OverrideConfiguredJarLocationFor(cfg, "com.android.bar", "libbar-old") + AssertStringEquals(t, "", "platform", apex) + AssertStringEquals(t, "", "libbar-new", jar) + + apex, jar = OverrideConfiguredJarLocationFor(cfg, "platform", "libbar-old") + AssertStringEquals(t, "", "platform", apex) + AssertStringEquals(t, "", "libbar-old", jar) +} diff --git a/android/fixture.go b/android/fixture.go index dbc3bc5e0..6660afd65 100644 --- a/android/fixture.go +++ b/android/fixture.go @@ -369,7 +369,7 @@ func FixtureModifyEnv(mutator func(env map[string]string)) FixturePreparer { // Allow access to the product variables when preparing the fixture. type FixtureProductVariables struct { - *productVariables + *ProductVariables } // Modify product variables. diff --git a/android/module.go b/android/module.go index 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/paths.go b/android/paths.go index fda4d2f46..e16cb3781 100644 --- a/android/paths.go +++ b/android/paths.go @@ -396,7 +396,7 @@ func ExistentPathsForSources(ctx PathGlobContext, paths []string) Paths { // // Properties passed as the paths argument must have been annotated with struct tag // `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the -// path_deps mutator. +// pathdeps mutator. // If a requested module is not found as a dependency: // - if ctx.Config().AllowMissingDependencies() is true, this module to be marked as having // missing dependencies @@ -425,7 +425,7 @@ type SourceInput struct { // excluding the items (similarly resolved // Properties passed as the paths argument must have been annotated with struct tag // `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the -// path_deps mutator. +// pathdeps mutator. // If a requested module is not found as a dependency: // - if ctx.Config().AllowMissingDependencies() is true, this module to be marked as having // missing dependencies @@ -560,7 +560,7 @@ func GetModuleFromPathDep(ctx ModuleWithDepsPathContext, moduleName, tag string) // and a list of the module names of missing module dependencies are returned as the second return. // Properties passed as the paths argument must have been annotated with struct tag // `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the -// path_deps mutator. +// pathdeps mutator. func PathsAndMissingDepsForModuleSrcExcludes(ctx ModuleMissingDepsPathContext, paths, excludes []string) (Paths, []string) { return PathsAndMissingDepsRelativeToModuleSourceDir(SourceInput{ Context: ctx, diff --git a/android/rule_builder.go b/android/rule_builder.go index 155fbdf71..777c1cfc3 100644 --- a/android/rule_builder.go +++ b/android/rule_builder.go @@ -53,6 +53,7 @@ type RuleBuilder struct { remoteable RemoteRuleSupports rbeParams *remoteexec.REParams outDir WritablePath + sboxOutSubDir string sboxTools bool sboxInputs bool sboxManifestPath WritablePath @@ -65,9 +66,18 @@ func NewRuleBuilder(pctx PackageContext, ctx BuilderContext) *RuleBuilder { pctx: pctx, ctx: ctx, temporariesSet: make(map[WritablePath]bool), + sboxOutSubDir: sboxOutSubDir, } } +// SetSboxOutDirDirAsEmpty sets the out subdirectory to an empty string +// This is useful for sandboxing actions that change the execution root to a path in out/ (e.g mixed builds) +// For such actions, SetSboxOutDirDirAsEmpty ensures that the path does not become $SBOX_SANDBOX_DIR/out/out/bazel/output/execroot/__main__/... +func (rb *RuleBuilder) SetSboxOutDirDirAsEmpty() *RuleBuilder { + rb.sboxOutSubDir = "" + return rb +} + // RuleBuilderInstall is a tuple of install from and to locations. type RuleBuilderInstall struct { From Path @@ -582,12 +592,10 @@ func (r *RuleBuilder) Build(name string, desc string) { // Add copy rules to the manifest to copy each output file from the sbox directory. // to the output directory after running the commands. - sboxOutputs := make([]string, len(outputs)) - for i, output := range outputs { + for _, output := range outputs { rel := Rel(r.ctx, r.outDir.String(), output.String()) - sboxOutputs[i] = filepath.Join(sboxOutDir, rel) command.CopyAfter = append(command.CopyAfter, &sbox_proto.Copy{ - From: proto.String(filepath.Join(sboxOutSubDir, rel)), + From: proto.String(filepath.Join(r.sboxOutSubDir, rel)), To: proto.String(output.String()), }) } diff --git a/android/sdk_version_test.go b/android/sdk_version_test.go index ea99c4d62..30bd002c2 100644 --- a/android/sdk_version_test.go +++ b/android/sdk_version_test.go @@ -75,7 +75,7 @@ func TestSdkSpecFrom(t *testing.T) { config := NullConfig("", "") - config.productVariables = productVariables{ + config.productVariables = ProductVariables{ Platform_sdk_version: intPtr(31), Platform_sdk_codename: stringPtr("Tiramisu"), Platform_version_active_codenames: []string{"Tiramisu"}, diff --git a/android/test_config.go b/android/test_config.go index 28d9ec403..2a59d9228 100644 --- a/android/test_config.go +++ b/android/test_config.go @@ -35,7 +35,7 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string envCopy["PATH"] = os.Getenv("PATH") config := &config{ - productVariables: productVariables{ + productVariables: ProductVariables{ DeviceName: stringPtr("test_device"), DeviceProduct: stringPtr("test_product"), Platform_sdk_version: intPtr(30), diff --git a/android/util.go b/android/util.go index e17d7b213..5375373a6 100644 --- a/android/util.go +++ b/android/util.go @@ -137,19 +137,17 @@ func SortedUniqueStringValues(m interface{}) []string { } // IndexList returns the index of the first occurrence of the given string in the list or -1 -func IndexList(s string, list []string) int { +func IndexList[T comparable](t T, list []T) int { for i, l := range list { - if l == s { + if l == t { return i } } - return -1 } -// InList checks if the string belongs to the list -func InList(s string, list []string) bool { - return IndexList(s, list) != -1 +func InList[T comparable](t T, list []T) bool { + return IndexList(t, list) != -1 } func setFromList[T comparable](l []T) map[T]bool { diff --git a/android/variable.go b/android/variable.go index 3bec854ea..2a9e7cd5b 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,12 +184,19 @@ 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"` } var defaultProductVariables interface{} = variableProperties{} -type productVariables struct { +type ProductVariables struct { // Suffix to add to generated Makefiles Make_suffix *string `json:",omitempty"` @@ -275,6 +286,7 @@ 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"` @@ -401,9 +413,10 @@ type productVariables struct { WithDexpreopt bool `json:",omitempty"` - ManifestPackageNameOverrides []string `json:",omitempty"` - CertificateOverrides []string `json:",omitempty"` - PackageNameOverrides []string `json:",omitempty"` + ManifestPackageNameOverrides []string `json:",omitempty"` + CertificateOverrides []string `json:",omitempty"` + PackageNameOverrides []string `json:",omitempty"` + ConfiguredJarLocationOverrides []string `json:",omitempty"` ApexGlobalMinSdkVersionOverride *string `json:",omitempty"` @@ -456,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"` @@ -474,6 +489,8 @@ type productVariables struct { ReleaseVersion string `json:",omitempty"` ReleaseAconfigValueSets []string `json:",omitempty"` + + KeepVndk *bool `json:",omitempty"` } func boolPtr(v bool) *bool { @@ -488,8 +505,8 @@ func stringPtr(v string) *string { return &v } -func (v *productVariables) SetDefaultConfig() { - *v = productVariables{ +func (v *ProductVariables) SetDefaultConfig() { + *v = ProductVariables{ BuildNumberFile: stringPtr("build_number.txt"), Platform_version_name: stringPtr("S"), @@ -526,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{}}, 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 b67535a18..ed780338a 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" @@ -5587,6 +5591,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { checkHiddenAPIIndexFromFlagsInputs(t, ctx, ` my-bootclasspath-fragment/index.csv out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv + out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv `) }) @@ -5664,6 +5669,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { checkHiddenAPIIndexFromFlagsInputs(t, ctx, ` my-bootclasspath-fragment/index.csv out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv + out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv `) myApex := ctx.ModuleForTests("myapex", "android_common_myapex").Module() @@ -5758,6 +5764,28 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { t.Run("prebuilt library preferred with source", func(t *testing.T) { bp := ` + apex { + name: "myapex", + key: "myapex.key", + updatable: false, + bootclasspath_fragments: ["my-bootclasspath-fragment"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + bootclasspath_fragment { + name: "my-bootclasspath-fragment", + contents: ["libfoo", "libbar"], + apex_available: ["myapex"], + hidden_api: { + split_packages: ["*"], + }, + } + prebuilt_apex { name: "myapex", arch: { @@ -5773,6 +5801,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { prebuilt_bootclasspath_fragment { name: "my-bootclasspath-fragment", + prefer: true, contents: ["libfoo", "libbar"], apex_available: ["myapex"], hidden_api: { @@ -5797,6 +5826,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { name: "libfoo", srcs: ["foo/bar/MyClass.java"], apex_available: ["myapex"], + installable: true, } java_sdk_library_import { @@ -5815,6 +5845,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { srcs: ["foo/bar/MyClass.java"], unsafe_ignore_missing_latest_api: true, apex_available: ["myapex"], + compile_dex: true, } ` @@ -5827,6 +5858,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { checkHiddenAPIIndexFromFlagsInputs(t, ctx, ` my-bootclasspath-fragment/index.csv out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv + out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv `) }) @@ -5835,8 +5867,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { apex { name: "myapex", key: "myapex.key", - java_libs: ["libfoo", "libbar"], updatable: false, + bootclasspath_fragments: ["my-bootclasspath-fragment"], } apex_key { @@ -5845,6 +5877,15 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { private_key: "testkey.pem", } + bootclasspath_fragment { + name: "my-bootclasspath-fragment", + contents: ["libfoo", "libbar"], + apex_available: ["myapex"], + hidden_api: { + split_packages: ["*"], + }, + } + prebuilt_apex { name: "myapex", arch: { @@ -5883,6 +5924,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { srcs: ["foo/bar/MyClass.java"], apex_available: ["myapex"], permitted_packages: ["foo"], + installable: true, } java_sdk_library_import { @@ -5900,6 +5942,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { unsafe_ignore_missing_latest_api: true, apex_available: ["myapex"], permitted_packages: ["bar"], + compile_dex: true, } ` @@ -5910,8 +5953,9 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { // Verify the correct module jars contribute to the hiddenapi index file. checkHiddenAPIIndexFromClassesInputs(t, ctx, ``) checkHiddenAPIIndexFromFlagsInputs(t, ctx, ` - my-bootclasspath-fragment/index.csv out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv + out/soong/.intermediates/my-bootclasspath-fragment/android_common_myapex/modular-hiddenapi/index.csv + out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv `) }) @@ -5921,7 +5965,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { name: "myapex", enabled: false, key: "myapex.key", - java_libs: ["libfoo", "libbar"], + bootclasspath_fragments: ["my-bootclasspath-fragment"], } apex_key { @@ -5930,6 +5974,16 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { private_key: "testkey.pem", } + bootclasspath_fragment { + name: "my-bootclasspath-fragment", + enabled: false, + contents: ["libfoo", "libbar"], + apex_available: ["myapex"], + hidden_api: { + split_packages: ["*"], + }, + } + prebuilt_apex { name: "myapex", arch: { @@ -5959,7 +6013,6 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { java_import { name: "libfoo", - prefer: true, jars: ["libfoo.jar"], apex_available: ["myapex"], permitted_packages: ["foo"], @@ -5967,13 +6020,14 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { java_library { name: "libfoo", + enabled: false, srcs: ["foo/bar/MyClass.java"], apex_available: ["myapex"], + installable: true, } java_sdk_library_import { name: "libbar", - prefer: true, public: { jars: ["libbar.jar"], }, @@ -5984,9 +6038,11 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { java_sdk_library { name: "libbar", + enabled: false, srcs: ["foo/bar/MyClass.java"], unsafe_ignore_missing_latest_api: true, apex_available: ["myapex"], + compile_dex: true, } ` @@ -5999,6 +6055,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { checkHiddenAPIIndexFromFlagsInputs(t, ctx, ` my-bootclasspath-fragment/index.csv out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv + out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv `) }) } @@ -8163,126 +8220,6 @@ func TestApexSetApksModuleAssignment(t *testing.T) { android.AssertArrayString(t, "extractor input", []string{"myapex.apks"}, extractedApex.Inputs.Strings()) } -func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, preparer android.FixturePreparer, fragments ...java.ApexVariantReference) { - t.Helper() - - bp := ` - java_library { - name: "some-updatable-apex-lib", - srcs: ["a.java"], - sdk_version: "current", - apex_available: [ - "some-updatable-apex", - ], - permitted_packages: ["some.updatable.apex.lib"], - min_sdk_version: "33", - } - - java_library { - name: "some-non-updatable-apex-lib", - srcs: ["a.java"], - apex_available: [ - "some-non-updatable-apex", - ], - compile_dex: true, - permitted_packages: ["some.non.updatable.apex.lib"], - } - - bootclasspath_fragment { - name: "some-non-updatable-fragment", - contents: ["some-non-updatable-apex-lib"], - apex_available: [ - "some-non-updatable-apex", - ], - hidden_api: { - split_packages: ["*"], - }, - } - - java_library { - name: "some-platform-lib", - srcs: ["a.java"], - sdk_version: "current", - installable: true, - } - - java_library { - name: "some-art-lib", - srcs: ["a.java"], - sdk_version: "current", - apex_available: [ - "com.android.art.debug", - ], - hostdex: true, - compile_dex: true, - min_sdk_version: "33", - } - - apex { - name: "some-updatable-apex", - key: "some-updatable-apex.key", - java_libs: ["some-updatable-apex-lib"], - updatable: true, - min_sdk_version: "33", - } - - apex { - name: "some-non-updatable-apex", - key: "some-non-updatable-apex.key", - bootclasspath_fragments: ["some-non-updatable-fragment"], - updatable: false, - } - - apex_key { - name: "some-updatable-apex.key", - } - - apex_key { - name: "some-non-updatable-apex.key", - } - - apex { - name: "com.android.art.debug", - key: "com.android.art.debug.key", - bootclasspath_fragments: ["art-bootclasspath-fragment"], - updatable: true, - min_sdk_version: "33", - } - - bootclasspath_fragment { - name: "art-bootclasspath-fragment", - image_name: "art", - contents: ["some-art-lib"], - apex_available: [ - "com.android.art.debug", - ], - hidden_api: { - split_packages: ["*"], - }, - } - - apex_key { - name: "com.android.art.debug.key", - } - - filegroup { - name: "some-updatable-apex-file_contexts", - srcs: [ - "system/sepolicy/apex/some-updatable-apex-file_contexts", - ], - } - - filegroup { - name: "some-non-updatable-apex-file_contexts", - srcs: [ - "system/sepolicy/apex/some-non-updatable-apex-file_contexts", - ], - } - ` - - testDexpreoptWithApexes(t, bp, errmsg, preparer, fragments...) -} - func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.FixturePreparer, fragments ...java.ApexVariantReference) *android.TestContext { t.Helper() @@ -8306,7 +8243,7 @@ func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.F result := android.GroupFixturePreparers( cc.PrepareForTestWithCcDefaultModules, java.PrepareForTestWithHiddenApiBuildComponents, - java.PrepareForTestWithJavaDefaultModules, + java.PrepareForTestWithDexpreopt, java.PrepareForTestWithJavaSdkLibraryFiles, PrepareForTestWithApexBuildComponents, preparer, @@ -8321,12 +8258,16 @@ func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.F platform_bootclasspath { name: "platform-bootclasspath", fragments: [ + {apex: "com.android.art", module: "art-bootclasspath-fragment"}, %s ], } `, insert)) } }), + // Dexpreopt for boot jars requires the ART boot image profile. + java.PrepareApexBootJarModule("com.android.art", "core-oj"), + dexpreopt.FixtureSetArtBootJars("com.android.art:core-oj"), dexpreopt.FixtureSetBootImageProfiles("art/build/boot/boot-image-profile.txt"), ). ExtendWithErrorHandler(errorHandler). @@ -8633,126 +8574,6 @@ func TestUpdatable_should_not_set_generate_classpaths_proto(t *testing.T) { ) } -func TestNoUpdatableJarsInBootImage(t *testing.T) { - // Set the BootJars in dexpreopt.GlobalConfig and productVariables to the same value. This can - // result in an invalid configuration as it does not set the ArtApexJars and allows art apex - // modules to be included in the BootJars. - prepareSetBootJars := func(bootJars ...string) android.FixturePreparer { - return android.GroupFixturePreparers( - dexpreopt.FixtureSetBootJars(bootJars...), - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.BootJars = android.CreateTestConfiguredJarList(bootJars) - }), - ) - } - - // Set the ArtApexJars and BootJars in dexpreopt.GlobalConfig and productVariables all to the - // same value. This can result in an invalid configuration as it allows non art apex jars to be - // specified in the ArtApexJars configuration. - prepareSetArtJars := func(bootJars ...string) android.FixturePreparer { - return android.GroupFixturePreparers( - dexpreopt.FixtureSetArtBootJars(bootJars...), - dexpreopt.FixtureSetBootJars(bootJars...), - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.BootJars = android.CreateTestConfiguredJarList(bootJars) - }), - ) - } - - t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) { - preparer := android.GroupFixturePreparers( - java.FixtureConfigureBootJars("com.android.art.debug:some-art-lib"), - java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"), - ) - fragments := []java.ApexVariantReference{ - { - Apex: proptools.StringPtr("com.android.art.debug"), - Module: proptools.StringPtr("art-bootclasspath-fragment"), - }, - { - Apex: proptools.StringPtr("some-non-updatable-apex"), - Module: proptools.StringPtr("some-non-updatable-fragment"), - }, - } - testNoUpdatableJarsInBootImage(t, "", preparer, fragments...) - }) - - t.Run("updatable jar from ART apex in the platform bootclasspath => error", func(t *testing.T) { - err := `module "some-art-lib" from updatable apexes \["com.android.art.debug"\] is not allowed in the platform bootclasspath` - // Update the dexpreopt BootJars directly. - preparer := android.GroupFixturePreparers( - prepareSetBootJars("com.android.art.debug:some-art-lib"), - java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"), - ) - testNoUpdatableJarsInBootImage(t, err, preparer) - }) - - t.Run("updatable jar from some other apex in the ART boot image => error", func(t *testing.T) { - err := `ArtApexJars expects this to be in apex "some-updatable-apex" but this is only in apexes.*"com.android.art.debug"` - // Update the dexpreopt ArtApexJars directly. - preparer := prepareSetArtJars("some-updatable-apex:some-updatable-apex-lib") - testNoUpdatableJarsInBootImage(t, err, preparer) - }) - - t.Run("non-updatable jar from some other apex in the ART boot image => error", func(t *testing.T) { - err := `ArtApexJars expects this to be in apex "some-non-updatable-apex" but this is only in apexes.*"com.android.art.debug"` - // Update the dexpreopt ArtApexJars directly. - preparer := prepareSetArtJars("some-non-updatable-apex:some-non-updatable-apex-lib") - testNoUpdatableJarsInBootImage(t, err, preparer) - }) - - t.Run("updatable jar from some other apex in the platform bootclasspath => error", func(t *testing.T) { - err := `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the platform bootclasspath` - preparer := android.GroupFixturePreparers( - java.FixtureConfigureBootJars("some-updatable-apex:some-updatable-apex-lib"), - java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"), - ) - testNoUpdatableJarsInBootImage(t, err, preparer) - }) - - t.Run("non-updatable jar from some other apex in the platform bootclasspath => ok", func(t *testing.T) { - preparer := java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib") - fragment := java.ApexVariantReference{ - Apex: proptools.StringPtr("some-non-updatable-apex"), - Module: proptools.StringPtr("some-non-updatable-fragment"), - } - testNoUpdatableJarsInBootImage(t, "", preparer, fragment) - }) - - t.Run("nonexistent jar in the ART boot image => error", func(t *testing.T) { - err := `"platform-bootclasspath" depends on undefined module "nonexistent"` - preparer := java.FixtureConfigureBootJars("platform:nonexistent") - testNoUpdatableJarsInBootImage(t, err, preparer) - }) - - t.Run("nonexistent jar in the platform bootclasspath => error", func(t *testing.T) { - err := `"platform-bootclasspath" depends on undefined module "nonexistent"` - preparer := java.FixtureConfigureBootJars("platform:nonexistent") - testNoUpdatableJarsInBootImage(t, err, preparer) - }) - - t.Run("platform jar in the ART boot image => error", func(t *testing.T) { - err := `ArtApexJars is invalid as it requests a platform variant of "some-platform-lib"` - // Update the dexpreopt ArtApexJars directly. - preparer := prepareSetArtJars("platform:some-platform-lib") - testNoUpdatableJarsInBootImage(t, err, preparer) - }) - - t.Run("platform jar in the platform bootclasspath => ok", func(t *testing.T) { - preparer := android.GroupFixturePreparers( - java.FixtureConfigureBootJars("platform:some-platform-lib"), - java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"), - ) - fragments := []java.ApexVariantReference{ - { - Apex: proptools.StringPtr("some-non-updatable-apex"), - Module: proptools.StringPtr("some-non-updatable-fragment"), - }, - } - testNoUpdatableJarsInBootImage(t, "", preparer, fragments...) - }) -} - func TestDexpreoptAccessDexFilesFromPrebuiltApex(t *testing.T) { preparer := java.FixtureConfigureApexBootJars("myapex:libfoo") t.Run("prebuilt no source", func(t *testing.T) { @@ -10736,6 +10557,7 @@ func TestTrimmedApex(t *testing.T) { src: "libc.so", min_sdk_version: "29", recovery_available: true, + vendor_available: true, } api_imports { name: "api_imports", diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go index 1b5288696..f30f7f666 100644 --- a/apex/bootclasspath_fragment_test.go +++ b/apex/bootclasspath_fragment_test.go @@ -46,78 +46,6 @@ var prepareForTestWithArtApex = android.GroupFixturePreparers( dexpreopt.FixtureSetBootImageProfiles("art/build/boot/boot-image-profile.txt"), ) -func TestBootclasspathFragments(t *testing.T) { - result := android.GroupFixturePreparers( - prepareForTestWithBootclasspathFragment, - // Configure some libraries in the art bootclasspath_fragment and platform_bootclasspath. - java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo", "platform:bar"), - prepareForTestWithArtApex, - - java.PrepareForTestWithJavaSdkLibraryFiles, - java.FixtureWithLastReleaseApis("foo"), - ).RunTestWithBp(t, ` - java_sdk_library { - name: "foo", - srcs: ["b.java"], - } - - java_library { - name: "bar", - srcs: ["b.java"], - installable: true, - } - - apex { - name: "com.android.art", - key: "com.android.art.key", - bootclasspath_fragments: ["art-bootclasspath-fragment"], - updatable: false, - } - - apex_key { - name: "com.android.art.key", - public_key: "com.android.art.avbpubkey", - private_key: "com.android.art.pem", - } - - java_library { - name: "baz", - apex_available: [ - "com.android.art", - ], - srcs: ["b.java"], - compile_dex: true, - } - - java_library { - name: "quuz", - apex_available: [ - "com.android.art", - ], - srcs: ["b.java"], - compile_dex: true, - } - - bootclasspath_fragment { - name: "art-bootclasspath-fragment", - image_name: "art", - // Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above. - contents: ["baz", "quuz"], - apex_available: [ - "com.android.art", - ], - hidden_api: { - split_packages: ["*"], - }, - } -`, - ) - - // Make sure that the art-bootclasspath-fragment is using the correct configuration. - checkBootclasspathFragment(t, result, "art-bootclasspath-fragment", "android_common_apex10000", - "com.android.art:baz,com.android.art:quuz") -} - func TestBootclasspathFragments_FragmentDependency(t *testing.T) { result := android.GroupFixturePreparers( prepareForTestWithBootclasspathFragment, @@ -248,16 +176,6 @@ func TestBootclasspathFragments_FragmentDependency(t *testing.T) { checkAPIScopeStubs("other", otherInfo, java.CorePlatformHiddenAPIScope) } -func checkBootclasspathFragment(t *testing.T, result *android.TestResult, moduleName, variantName string, expectedConfiguredModules string) { - t.Helper() - - bootclasspathFragment := result.ModuleForTests(moduleName, variantName).Module().(*java.BootclasspathFragmentModule) - - bootclasspathFragmentInfo := result.ModuleProvider(bootclasspathFragment, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo) - modules := bootclasspathFragmentInfo.Modules() - android.AssertStringEquals(t, "invalid modules for "+moduleName, expectedConfiguredModules, modules.String()) -} - func TestBootclasspathFragmentInArtApex(t *testing.T) { commonPreparer := android.GroupFixturePreparers( prepareForTestWithBootclasspathFragment, @@ -268,10 +186,10 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { name: "com.android.art", key: "com.android.art.key", bootclasspath_fragments: [ - "mybootclasspathfragment", + "art-bootclasspath-fragment", ], // bar (like foo) should be transitively included in this apex because it is part of the - // mybootclasspathfragment bootclasspath_fragment. + // art-bootclasspath-fragment bootclasspath_fragment. updatable: false, } @@ -280,42 +198,6 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { public_key: "testkey.avbpubkey", private_key: "testkey.pem", } - - java_library { - name: "foo", - srcs: ["b.java"], - installable: true, - apex_available: [ - "com.android.art", - ], - } - - java_library { - name: "bar", - srcs: ["b.java"], - installable: true, - apex_available: [ - "com.android.art", - ], - } - - java_import { - name: "foo", - jars: ["foo.jar"], - apex_available: [ - "com.android.art", - ], - compile_dex: true, - } - - java_import { - name: "bar", - jars: ["bar.jar"], - apex_available: [ - "com.android.art", - ], - compile_dex: true, - } `), ) @@ -330,7 +212,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { addSource := func(contents ...string) android.FixturePreparer { text := fmt.Sprintf(` bootclasspath_fragment { - name: "mybootclasspathfragment", + name: "art-bootclasspath-fragment", image_name: "art", %s apex_available: [ @@ -342,6 +224,19 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { } `, contentsInsert(contents)) + for _, content := range contents { + text += fmt.Sprintf(` + java_library { + name: "%[1]s", + srcs: ["%[1]s.java"], + installable: true, + apex_available: [ + "com.android.art", + ], + } + `, content) + } + return android.FixtureAddTextFile("art/build/boot/Android.bp", text) } @@ -357,11 +252,11 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { src: "com.android.art-arm.apex", }, }, - exported_bootclasspath_fragments: ["mybootclasspathfragment"], + exported_bootclasspath_fragments: ["art-bootclasspath-fragment"], } prebuilt_bootclasspath_fragment { - name: "mybootclasspathfragment", + name: "art-bootclasspath-fragment", image_name: "art", %s prefer: %t, @@ -369,14 +264,29 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { "com.android.art", ], hidden_api: { - annotation_flags: "mybootclasspathfragment/annotation-flags.csv", - metadata: "mybootclasspathfragment/metadata.csv", - index: "mybootclasspathfragment/index.csv", - stub_flags: "mybootclasspathfragment/stub-flags.csv", - all_flags: "mybootclasspathfragment/all-flags.csv", + annotation_flags: "hiddenapi/annotation-flags.csv", + metadata: "hiddenapi/metadata.csv", + index: "hiddenapi/index.csv", + stub_flags: "hiddenapi/stub-flags.csv", + all_flags: "hiddenapi/all-flags.csv", }, } `, contentsInsert(contents), prefer) + + for _, content := range contents { + text += fmt.Sprintf(` + java_import { + name: "%[1]s", + prefer: %[2]t, + jars: ["%[1]s.jar"], + apex_available: [ + "com.android.art", + ], + compile_dex: true, + } + `, content, prefer) + } + return android.FixtureAddTextFile("prebuilts/module_sdk/art/Android.bp", text) } @@ -387,6 +297,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { // Configure some libraries in the art bootclasspath_fragment that match the source // bootclasspath_fragment's contents property. java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"), + dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:foo", "com.android.art:bar"), addSource("foo", "bar"), java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"), ).RunTest(t) @@ -399,13 +310,13 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { }) java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{ + `art-bootclasspath-fragment`, `com.android.art.key`, - `mybootclasspathfragment`, }) // Make sure that the source bootclasspath_fragment copies its dex files to the predefined // locations for the art image. - module := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000") + module := result.ModuleForTests("dex_bootjars", "android_common") checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo") }) @@ -454,6 +365,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { // Configure some libraries in the art bootclasspath_fragment that match the source // bootclasspath_fragment's contents property. java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"), + dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:foo", "com.android.art:bar"), addSource("foo", "bar"), // Make sure that a preferred prebuilt with consistent contents doesn't affect the apex. @@ -469,14 +381,14 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { }) java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{ + `art-bootclasspath-fragment`, `com.android.art.key`, - `mybootclasspathfragment`, `prebuilt_com.android.art`, }) // Make sure that the prebuilt bootclasspath_fragment copies its dex files to the predefined // locations for the art image. - module := result.ModuleForTests("prebuilt_mybootclasspathfragment", "android_common_com.android.art") + module := result.ModuleForTests("dex_bootjars", "android_common") checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo") }) @@ -552,6 +464,7 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) { // Configure some libraries in the art bootclasspath_fragment. java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"), + dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:foo", "com.android.art:bar"), java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"), ) @@ -566,7 +479,7 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) { src: "com.android.art-arm.apex", }, }, - exported_bootclasspath_fragments: ["mybootclasspathfragment"], + exported_bootclasspath_fragments: ["art-bootclasspath-fragment"], } java_import { @@ -586,7 +499,7 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) { } prebuilt_bootclasspath_fragment { - name: "mybootclasspathfragment", + name: "art-bootclasspath-fragment", image_name: "art", // Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above. contents: ["foo", "bar"], @@ -594,11 +507,11 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) { "com.android.art", ], hidden_api: { - annotation_flags: "mybootclasspathfragment/annotation-flags.csv", - metadata: "mybootclasspathfragment/metadata.csv", - index: "mybootclasspathfragment/index.csv", - stub_flags: "mybootclasspathfragment/stub-flags.csv", - all_flags: "mybootclasspathfragment/all-flags.csv", + annotation_flags: "hiddenapi/annotation-flags.csv", + metadata: "hiddenapi/metadata.csv", + index: "hiddenapi/index.csv", + stub_flags: "hiddenapi/stub-flags.csv", + all_flags: "hiddenapi/all-flags.csv", }, } @@ -608,7 +521,7 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) { apex_name: "com.android.art", %s src: "com.mycompany.android.art.apex", - exported_bootclasspath_fragments: ["mybootclasspathfragment"], + exported_bootclasspath_fragments: ["art-bootclasspath-fragment"], } ` @@ -617,17 +530,17 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) { java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{ `com.android.art.apex.selector`, - `prebuilt_mybootclasspathfragment`, + `prebuilt_art-bootclasspath-fragment`, }) - java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_com.android.art", []string{ + java.CheckModuleDependencies(t, result.TestContext, "art-bootclasspath-fragment", "android_common_com.android.art", []string{ `com.android.art.deapexer`, `dex2oatd`, `prebuilt_bar`, `prebuilt_foo`, }) - module := result.ModuleForTests("mybootclasspathfragment", "android_common_com.android.art") + module := result.ModuleForTests("dex_bootjars", "android_common") checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo") }) diff --git a/apex/dexpreopt_bootjars_test.go b/apex/dexpreopt_bootjars_test.go index bba8bb6cb..2e828cade 100644 --- a/apex/dexpreopt_bootjars_test.go +++ b/apex/dexpreopt_bootjars_test.go @@ -138,8 +138,8 @@ func testDexpreoptBoot(t *testing.T, ruleFile string, expectedInputs, expectedOu prepareForTestWithArtApex, ).RunTestWithBp(t, fmt.Sprintf(bp, preferPrebuilt)) - platformBootclasspath := result.ModuleForTests("platform-bootclasspath", "android_common") - rule := platformBootclasspath.Output(ruleFile) + dexBootJars := result.ModuleForTests("dex_bootjars", "android_common") + rule := dexBootJars.Output(ruleFile) inputs := rule.Implicits.Strings() sort.Strings(inputs) @@ -155,15 +155,15 @@ func testDexpreoptBoot(t *testing.T, ruleFile string, expectedInputs, expectedOu } func TestDexpreoptBootJarsWithSourceArtApex(t *testing.T) { - ruleFile := "boot.art" + ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art" expectedInputs := []string{ "out/soong/dexpreopt_arm64/dex_bootjars_input/core-oj.jar", "out/soong/dexpreopt_arm64/dex_bootjars_input/foo.jar", "out/soong/dexpreopt_arm64/dex_bootjars_input/bar.jar", "out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar", - "out/soong/dexpreopt_arm64/dex_artjars/boot.prof", - "out/soong/dexpreopt_arm64/dex_bootjars/boot.prof", + "out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art-bootclasspath-fragment/boot.prof", + "out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof", } expectedOutputs := []string{ @@ -192,7 +192,7 @@ func TestDexpreoptBootJarsWithSourceArtApex(t *testing.T) { // The only difference is that the ART profile should be deapexed from the prebuilt APEX. Other // inputs and outputs should be the same as above. func TestDexpreoptBootJarsWithPrebuiltArtApex(t *testing.T) { - ruleFile := "boot.art" + ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art" expectedInputs := []string{ "out/soong/dexpreopt_arm64/dex_bootjars_input/core-oj.jar", @@ -200,7 +200,7 @@ func TestDexpreoptBootJarsWithPrebuiltArtApex(t *testing.T) { "out/soong/dexpreopt_arm64/dex_bootjars_input/bar.jar", "out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar", "out/soong/.intermediates/com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof", - "out/soong/dexpreopt_arm64/dex_bootjars/boot.prof", + "out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof", } expectedOutputs := []string{ diff --git a/bazel/aquery.go b/bazel/aquery.go index 480158c11..3428328bd 100644 --- a/bazel/aquery.go +++ b/bazel/aquery.go @@ -116,6 +116,9 @@ type BuildStatement struct { InputDepsetHashes []string InputPaths []string FileContents string + // If ShouldRunInSbox is true, Soong will use sbox to created an isolated environment + // and run the mixed build action there + ShouldRunInSbox bool } // A helper type for aquery processing which facilitates retrieval of path IDs from their @@ -496,6 +499,12 @@ func (a *aqueryArtifactHandler) normalActionBuildStatement(actionEntry *analysis Env: actionEntry.EnvironmentVariables, Mnemonic: actionEntry.Mnemonic, } + if buildStatement.Mnemonic == "GoToolchainBinaryBuild" { + // Unlike b's execution root, mixed build execution root contains a symlink to prebuilts/go + // This causes issues for `GOCACHE=$(mktemp -d) go build ...` + // To prevent this, sandbox this action in mixed builds as well + buildStatement.ShouldRunInSbox = true + } return buildStatement, nil } diff --git a/bazel/configurability.go b/bazel/configurability.go index 8f63ec45b..d962a1dac 100644 --- a/bazel/configurability.go +++ b/bazel/configurability.go @@ -74,6 +74,8 @@ const ( InApex = "in_apex" NonApex = "non_apex" + + ErrorproneDisabled = "errorprone_disabled" ) func PowerSetWithoutEmptySet[T any](items []T) [][]T { @@ -216,6 +218,11 @@ var ( NonApex: "//build/bazel/rules/apex:non_apex", ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, } + + errorProneMap = map[string]string{ + ErrorproneDisabled: "//build/bazel/rules/java/errorprone:errorprone_globally_disabled", + ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, + } ) // basic configuration types @@ -229,6 +236,7 @@ const ( productVariables osAndInApex inApex + errorProneDisabled ) func osArchString(os string, arch string) string { @@ -237,13 +245,14 @@ func osArchString(os string, arch string) string { func (ct configurationType) String() string { return map[configurationType]string{ - noConfig: "no_config", - arch: "arch", - os: "os", - osArch: "arch_os", - productVariables: "product_variables", - osAndInApex: "os_in_apex", - inApex: "in_apex", + noConfig: "no_config", + arch: "arch", + os: "os", + osArch: "arch_os", + productVariables: "product_variables", + osAndInApex: "os_in_apex", + inApex: "in_apex", + errorProneDisabled: "errorprone_disabled", }[ct] } @@ -274,6 +283,10 @@ func (ct configurationType) validateConfig(config string) { if _, ok := inApexMap[config]; !ok { panic(fmt.Errorf("Unknown in_apex config: %s", config)) } + case errorProneDisabled: + if _, ok := errorProneMap[config]; !ok { + panic(fmt.Errorf("Unknown errorprone config: %s", config)) + } default: panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct)) } @@ -303,6 +316,8 @@ func (ca ConfigurationAxis) SelectKey(config string) string { return config case inApex: return inApexMap[config] + case errorProneDisabled: + return errorProneMap[config] default: panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType)) } @@ -321,6 +336,8 @@ var ( OsAndInApexAxis = ConfigurationAxis{configurationType: osAndInApex} // An axis for in_apex-specific configurations InApexAxis = ConfigurationAxis{configurationType: inApex} + + ErrorProneAxis = ConfigurationAxis{configurationType: errorProneDisabled} ) // ProductVariableConfigurationAxis returns an axis for the given product variable diff --git a/bazel/properties.go b/bazel/properties.go index e22f4dbe7..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 } @@ -766,7 +801,7 @@ func (lla *LabelListAttribute) SetSelectValue(axis ConfigurationAxis, config str switch axis.configurationType { case noConfig: lla.Value = list - case arch, os, osArch, productVariables, osAndInApex, inApex: + case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled: if lla.ConfigurableValues == nil { lla.ConfigurableValues = make(configurableLabelLists) } @@ -782,7 +817,7 @@ func (lla *LabelListAttribute) SelectValue(axis ConfigurationAxis, config string switch axis.configurationType { case noConfig: return lla.Value - case arch, os, osArch, productVariables, osAndInApex, inApex: + case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled: return lla.ConfigurableValues[axis][config] default: panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis)) @@ -1346,7 +1381,7 @@ func (sla *StringListAttribute) SetSelectValue(axis ConfigurationAxis, config st switch axis.configurationType { case noConfig: sla.Value = list - case arch, os, osArch, productVariables, osAndInApex: + case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled: if sla.ConfigurableValues == nil { sla.ConfigurableValues = make(configurableStringLists) } @@ -1362,7 +1397,7 @@ func (sla *StringListAttribute) SelectValue(axis ConfigurationAxis, config strin switch axis.configurationType { case noConfig: return sla.Value - case arch, os, osArch, productVariables, osAndInApex: + case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled: return sla.ConfigurableValues[axis][config] default: panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis)) 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 782a88c72..4a3786feb 100644 --- a/bp2build/Android.bp +++ b/bp2build/Android.bp @@ -19,6 +19,7 @@ bootstrap_go_package { "testing.go", ], deps: [ + "blueprint-bootstrap", "soong-aidl-library", "soong-android", "soong-android-allowlists", @@ -37,6 +38,7 @@ bootstrap_go_package { "soong-ui-metrics", ], testSrcs: [ + "go_conversion_test.go", "aar_conversion_test.go", "aidl_library_conversion_test.go", "android_app_certificate_conversion_test.go", @@ -44,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/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go index 7f7aa6a3a..d1b4d4061 100644 --- a/bp2build/android_app_conversion_test.go +++ b/bp2build/android_app_conversion_test.go @@ -349,7 +349,7 @@ android_app { }}) } -func TestAndroidAppMinSdkProvided(t *testing.T) { +func TestAndroidAppManifestSdkVersionsProvided(t *testing.T) { runAndroidAppTestCase(t, Bp2buildTestCase{ Description: "Android app with value for min_sdk_version", ModuleTypeUnderTest: "android_app", @@ -359,7 +359,9 @@ func TestAndroidAppMinSdkProvided(t *testing.T) { android_app { name: "foo", sdk_version: "current", - min_sdk_version: "24", + min_sdk_version: "24", + max_sdk_version: "30", + target_sdk_version: "29", } `, ExpectedBazelTargets: []string{ @@ -367,14 +369,16 @@ android_app { "manifest": `"AndroidManifest.xml"`, "resource_files": `[]`, "manifest_values": `{ + "maxSdkVersion": "30", "minSdkVersion": "24", + "targetSdkVersion": "29", }`, "sdk_version": `"current"`, }), }}) } -func TestAndroidAppMinSdkDefaultToSdkVersion(t *testing.T) { +func TestAndroidAppMinAndTargetSdkDefaultToSdkVersion(t *testing.T) { runAndroidAppTestCase(t, Bp2buildTestCase{ Description: "Android app with value for sdk_version", ModuleTypeUnderTest: "android_app", @@ -392,6 +396,7 @@ android_app { "resource_files": `[]`, "manifest_values": `{ "minSdkVersion": "30", + "targetSdkVersion": "30", }`, "sdk_version": `"30"`, }), diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go index b22cb2861..cfe52db47 100644 --- a/bp2build/bp2build.go +++ b/bp2build/bp2build.go @@ -80,6 +80,12 @@ func Codegen(ctx *CodegenContext) *CodegenMetrics { os.Exit(1) } bp2buildFiles := CreateBazelFiles(ctx.Config(), nil, res.buildFileToTargets, ctx.mode) + injectionFiles, additionalBp2buildFiles, err := CreateSoongInjectionDirFiles(ctx, res.metrics) + if err != nil { + fmt.Printf("%s\n", err.Error()) + os.Exit(1) + } + bp2buildFiles = append(bp2buildFiles, additionalBp2buildFiles...) writeFiles(ctx, bp2buildDir, bp2buildFiles) // Delete files under the bp2build root which weren't just written. An // alternative would have been to delete the whole directory and write these @@ -88,11 +94,6 @@ func Codegen(ctx *CodegenContext) *CodegenMetrics { // performance implications. deleteFilesExcept(ctx, bp2buildDir, bp2buildFiles) - injectionFiles, err := CreateSoongInjectionDirFiles(ctx, res.metrics) - if err != nil { - fmt.Printf("%s\n", err.Error()) - os.Exit(1) - } writeFiles(ctx, android.PathForOutput(ctx, bazel.SoongInjectionDirName), injectionFiles) starlarkDeps, err := starlark_import.GetNinjaDeps() if err != nil { @@ -107,20 +108,20 @@ func Codegen(ctx *CodegenContext) *CodegenMetrics { // This includes // 1. config value(s) that are hardcoded in Soong // 2. product_config variables -func CreateSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, error) { +func CreateSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, []BazelFile, error) { var ret []BazelFile - productConfigFiles, err := CreateProductConfigFiles(ctx) + productConfigInjectionFiles, productConfigBp2BuildDirFiles, err := CreateProductConfigFiles(ctx) if err != nil { - return nil, err + return nil, nil, err } - ret = append(ret, productConfigFiles...) + ret = append(ret, productConfigInjectionFiles...) injectionFiles, err := soongInjectionFiles(ctx.Config(), metrics) if err != nil { - return nil, err + return nil, nil, err } - ret = append(ret, injectionFiles...) - return ret, nil + ret = append(injectionFiles, ret...) + return ret, productConfigBp2BuildDirFiles, nil } // Get the output directory and create it if it doesn't exist. diff --git a/bp2build/bp2build_product_config.go b/bp2build/bp2build_product_config.go index 72244961d..f56e6d86e 100644 --- a/bp2build/bp2build_product_config.go +++ b/bp2build/bp2build_product_config.go @@ -1,14 +1,21 @@ package bp2build import ( + "android/soong/android" + "android/soong/starlark_import" + "encoding/json" "fmt" "os" "path/filepath" + "reflect" "strings" + + "github.com/google/blueprint/proptools" + "go.starlark.net/starlark" ) func CreateProductConfigFiles( - ctx *CodegenContext) ([]BazelFile, error) { + ctx *CodegenContext) ([]BazelFile, []BazelFile, error) { cfg := &ctx.config targetProduct := "unknown" if cfg.HasDeviceProduct() { @@ -25,9 +32,14 @@ func CreateProductConfigFiles( if !strings.HasPrefix(productVariablesFileName, "/") { productVariablesFileName = filepath.Join(ctx.topDir, productVariablesFileName) } - bytes, err := os.ReadFile(productVariablesFileName) + productVariablesBytes, err := os.ReadFile(productVariablesFileName) + if err != nil { + return nil, nil, err + } + productVariables := android.ProductVariables{} + err = json.Unmarshal(productVariablesBytes, &productVariables) if err != nil { - return nil, err + return nil, nil, err } // TODO(b/249685973): the name is product_config_platforms because product_config @@ -39,11 +51,16 @@ func CreateProductConfigFiles( "{VARIANT}", targetBuildVariant, "{PRODUCT_FOLDER}", currentProductFolder) - result := []BazelFile{ + platformMappingContent, err := platformMappingContent(productReplacer.Replace("@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"), &productVariables) + if err != nil { + return nil, nil, err + } + + injectionDirFiles := []BazelFile{ newFile( currentProductFolder, "soong.variables.bzl", - `variables = json.decode("""`+strings.ReplaceAll(string(bytes), "\\", "\\\\")+`""")`), + `variables = json.decode("""`+strings.ReplaceAll(string(productVariablesBytes), "\\", "\\\\")+`""")`), newFile( currentProductFolder, "BUILD", @@ -99,6 +116,7 @@ product_labels = [ "product_config_platforms", "common.bazelrc", productReplacer.Replace(` +build --platform_mappings=platform_mappings build --platforms @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64 build:android --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT} @@ -120,6 +138,148 @@ build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_lin build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_darwin_x86_64 `)), } + bp2buildDirFiles := []BazelFile{ + newFile( + "", + "platform_mappings", + platformMappingContent), + } + return injectionDirFiles, bp2buildDirFiles, nil +} + +func platformMappingContent(mainProductLabel string, mainProductVariables *android.ProductVariables) (string, error) { + productsForTesting, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing") + if err != nil { + return "", err + } + var result strings.Builder + result.WriteString("platforms:\n") + platformMappingSingleProduct(mainProductLabel, mainProductVariables, &result) + for product, productVariablesStarlark := range productsForTesting { + productVariables, err := starlarkMapToProductVariables(productVariablesStarlark) + if err != nil { + return "", err + } + platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables, &result) + } + return result.String(), nil +} + +var bazelPlatformSuffixes = []string{ + "", + "_darwin_arm64", + "_darwin_x86_64", + "_linux_bionic_arm64", + "_linux_bionic_x86_64", + "_linux_musl_x86", + "_linux_musl_x86_64", + "_linux_x86", + "_linux_x86_64", + "_windows_x86", + "_windows_x86_64", +} + +func platformMappingSingleProduct(label string, productVariables *android.ProductVariables, result *strings.Builder) { + targetBuildVariant := "user" + if proptools.Bool(productVariables.Eng) { + targetBuildVariant = "eng" + } else if proptools.Bool(productVariables.Debuggable) { + targetBuildVariant = "userdebug" + } + + for _, suffix := range bazelPlatformSuffixes { + result.WriteString(" ") + result.WriteString(label) + result.WriteString(suffix) + result.WriteString("\n") + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:always_use_prebuilt_sdks=%t\n", proptools.Bool(productVariables.Always_use_prebuilt_sdks))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:apex_global_min_sdk_version_override=%s\n", proptools.String(productVariables.ApexGlobalMinSdkVersionOverride))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_id=%s\n", proptools.String(productVariables.BuildId))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_version_tags=%s\n", strings.Join(productVariables.BuildVersionTags, ","))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:certificate_overrides=%s\n", strings.Join(productVariables.CertificateOverrides, ","))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:cfi_exclude_paths=%s\n", strings.Join(productVariables.CFIExcludePaths, ","))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:cfi_include_paths=%s\n", strings.Join(productVariables.CFIIncludePaths, ","))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:compressed_apex=%t\n", proptools.Bool(productVariables.CompressedApex))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:default_app_certificate=%s\n", proptools.String(productVariables.DefaultAppCertificate))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_abi=%s\n", strings.Join(productVariables.DeviceAbi, ","))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_max_page_size_supported=%s\n", proptools.String(productVariables.DeviceMaxPageSizeSupported))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_name=%s\n", proptools.String(productVariables.DeviceName))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_product=%s\n", proptools.String(productVariables.DeviceProduct))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:enable_cfi=%t\n", proptools.BoolDefault(productVariables.EnableCFI, true))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:manifest_package_name_overrides=%s\n", strings.Join(productVariables.ManifestPackageNameOverrides, ","))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:platform_version_name=%s\n", proptools.String(productVariables.Platform_version_name))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:product_brand=%s\n", productVariables.ProductBrand)) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:product_manufacturer=%s\n", productVariables.ProductManufacturer)) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:target_build_variant=%s\n", targetBuildVariant)) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:tidy_checks=%s\n", proptools.String(productVariables.TidyChecks))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:unbundled_build=%t\n", proptools.Bool(productVariables.Unbundled_build))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:unbundled_build_apps=%s\n", strings.Join(productVariables.Unbundled_build_apps, ","))) + } +} + +func starlarkMapToProductVariables(in map[string]starlark.Value) (android.ProductVariables, error) { + result := android.ProductVariables{} + productVarsReflect := reflect.ValueOf(&result).Elem() + for i := 0; i < productVarsReflect.NumField(); i++ { + field := productVarsReflect.Field(i) + fieldType := productVarsReflect.Type().Field(i) + name := fieldType.Name + if name == "BootJars" || name == "ApexBootJars" || name == "VendorVars" || + name == "VendorSnapshotModules" || name == "RecoverySnapshotModules" { + // These variables have more complicated types, and we don't need them right now + continue + } + if _, ok := in[name]; ok { + switch field.Type().Kind() { + case reflect.Bool: + val, err := starlark_import.Unmarshal[bool](in[name]) + if err != nil { + return result, err + } + field.SetBool(val) + case reflect.String: + val, err := starlark_import.Unmarshal[string](in[name]) + if err != nil { + return result, err + } + field.SetString(val) + case reflect.Slice: + if field.Type().Elem().Kind() != reflect.String { + return result, fmt.Errorf("slices of types other than strings are unimplemented") + } + val, err := starlark_import.UnmarshalReflect(in[name], field.Type()) + if err != nil { + return result, err + } + field.Set(val) + case reflect.Pointer: + switch field.Type().Elem().Kind() { + case reflect.Bool: + val, err := starlark_import.UnmarshalNoneable[bool](in[name]) + if err != nil { + return result, err + } + field.Set(reflect.ValueOf(val)) + case reflect.String: + val, err := starlark_import.UnmarshalNoneable[string](in[name]) + if err != nil { + return result, err + } + field.Set(reflect.ValueOf(val)) + case reflect.Int: + val, err := starlark_import.UnmarshalNoneable[int](in[name]) + if err != nil { + return result, err + } + field.Set(reflect.ValueOf(val)) + default: + return result, fmt.Errorf("pointers of types other than strings/bools are unimplemented: %s", field.Type().Elem().Kind().String()) + } + default: + return result, fmt.Errorf("unimplemented type: %s", field.Type().String()) + } + } + } return result, nil } diff --git a/bp2build/bp2build_product_config_test.go b/bp2build/bp2build_product_config_test.go new file mode 100644 index 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 46a5bd8cb..0e6596bf7 100644 --- a/bp2build/build_conversion.go +++ b/bp2build/build_conversion.go @@ -30,6 +30,7 @@ import ( "android/soong/starlark_fmt" "android/soong/ui/metrics/bp2build_metrics_proto" "github.com/google/blueprint" + "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/proptools" ) @@ -252,6 +253,224 @@ func (r conversionResults) BuildDirToTargets() map[string]BazelTargets { return r.buildFileToTargets } +// struct to store state of go bazel targets +// this implements bp2buildModule interface and is passed to generateBazelTargets +type goBazelTarget struct { + targetName string + targetPackage string + bazelRuleClass string + bazelRuleLoadLocation string + bazelAttributes []interface{} +} + +var _ bp2buildModule = (*goBazelTarget)(nil) + +func (g goBazelTarget) TargetName() string { + return g.targetName +} + +func (g goBazelTarget) TargetPackage() string { + return g.targetPackage +} + +func (g goBazelTarget) BazelRuleClass() string { + return g.bazelRuleClass +} + +func (g goBazelTarget) BazelRuleLoadLocation() string { + return g.bazelRuleLoadLocation +} + +func (g goBazelTarget) BazelAttributes() []interface{} { + return g.bazelAttributes +} + +// Creates a target_compatible_with entry that is *not* compatible with android +func targetNotCompatibleWithAndroid() bazel.LabelListAttribute { + ret := bazel.LabelListAttribute{} + ret.SetSelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid, + bazel.MakeLabelList( + []bazel.Label{ + bazel.Label{ + Label: "@platforms//:incompatible", + }, + }, + ), + ) + return ret +} + +// helper function to return labels for srcs used in bootstrap_go_package and bootstrap_go_binary +// this function has the following limitations which make it unsuitable for widespread use +// - wildcard patterns in srcs +// This is ok for go since build/blueprint does not support it. +// +// Prefer to use `BazelLabelForModuleSrc` instead +func goSrcLabels(cfg android.Config, moduleDir string, srcs []string, linuxSrcs, darwinSrcs []string) bazel.LabelListAttribute { + labels := func(srcs []string) bazel.LabelList { + ret := []bazel.Label{} + for _, src := range srcs { + srcLabel := bazel.Label{ + Label: src, + } + ret = append(ret, srcLabel) + } + // Respect package boundaries + return android.TransformSubpackagePaths( + cfg, + moduleDir, + bazel.MakeLabelList(ret), + ) + } + + ret := bazel.LabelListAttribute{} + // common + ret.SetSelectValue(bazel.NoConfigAxis, "", labels(srcs)) + // linux + ret.SetSelectValue(bazel.OsConfigurationAxis, bazel.OsLinux, labels(linuxSrcs)) + // darwin + ret.SetSelectValue(bazel.OsConfigurationAxis, bazel.OsDarwin, labels(darwinSrcs)) + return ret +} + +func goDepLabels(deps []string, goModulesMap nameToGoLibraryModule) bazel.LabelListAttribute { + labels := []bazel.Label{} + for _, dep := range deps { + moduleDir := goModulesMap[dep].Dir + if moduleDir == "." { + moduleDir = "" + } + label := bazel.Label{ + Label: fmt.Sprintf("//%s:%s", moduleDir, dep), + } + labels = append(labels, label) + } + return bazel.MakeLabelListAttribute(bazel.MakeLabelList(labels)) +} + +// attributes common to blueprint_go_binary and bootstap_go_package +type goAttributes struct { + Importpath bazel.StringAttribute + Srcs bazel.LabelListAttribute + Deps bazel.LabelListAttribute + Target_compatible_with bazel.LabelListAttribute +} + +func generateBazelTargetsGoPackage(ctx *android.Context, g *bootstrap.GoPackage, goModulesMap nameToGoLibraryModule) ([]BazelTarget, []error) { + ca := android.CommonAttributes{ + Name: g.Name(), + } + + // 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 + // Bazel OTOH + // 1. requires C to be listed in `deps` expllicity. + // 2. does not require C to be listed if src of A does not import C + // + // 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) + + ga := goAttributes{ + Importpath: bazel.StringAttribute{ + Value: proptools.StringPtr(g.GoPkgPath()), + }, + Srcs: goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs()), + Deps: goDepLabels( + android.FirstUniqueStrings(transitiveDeps), + goModulesMap, + ), + Target_compatible_with: targetNotCompatibleWithAndroid(), + } + + lib := goBazelTarget{ + targetName: g.Name(), + targetPackage: ctx.ModuleDir(g), + bazelRuleClass: "go_library", + 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} + } + return []BazelTarget{libTarget}, nil +} + +type goLibraryModule struct { + Dir string + Deps []string +} + +type nameToGoLibraryModule map[string]goLibraryModule + +// Visit each module in the graph +// If a module is of type `bootstrap_go_package`, return a map containing metadata like its dir and deps +func createGoLibraryModuleMap(ctx *android.Context) nameToGoLibraryModule { + ret := nameToGoLibraryModule{} + ctx.VisitAllModules(func(m blueprint.Module) { + moduleType := ctx.ModuleType(m) + // We do not need to store information about blueprint_go_binary since it does not have any rdeps + if moduleType == "bootstrap_go_package" { + ret[m.Name()] = goLibraryModule{ + Dir: ctx.ModuleDir(m), + Deps: m.(*bootstrap.GoPackage).Deps(), + } + } + }) + return ret +} + +// Returns the deps in the transitive closure of a go target +func transitiveGoDeps(directDeps []string, goModulesMap nameToGoLibraryModule) []string { + allDeps := directDeps + i := 0 + for i < len(allDeps) { + curr := allDeps[i] + allDeps = append(allDeps, goModulesMap[curr].Deps...) + i += 1 + } + allDeps = android.SortedUniqueStrings(allDeps) + return allDeps +} + +func generateBazelTargetsGoBinary(ctx *android.Context, g *bootstrap.GoBinary, goModulesMap nameToGoLibraryModule) ([]BazelTarget, []error) { + ca := android.CommonAttributes{ + Name: g.Name(), + } + + // 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 + // Bazel OTOH + // 1. requires C to be listed in `deps` expllicity. + // 2. does not require C to be listed if src of A does not import C + // + // 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) + + ga := goAttributes{ + Srcs: goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs()), + Deps: goDepLabels(transitiveDeps, goModulesMap), + Target_compatible_with: targetNotCompatibleWithAndroid(), + } + + bin := goBazelTarget{ + targetName: g.Name(), + targetPackage: ctx.ModuleDir(g), + bazelRuleClass: "go_binary", + bazelRuleLoadLocation: "@io_bazel_rules_go//go:def.bzl", + bazelAttributes: []interface{}{&ca, &ga}, + } + // TODO - b/284483729: Create go_test target from testSrcs + binTarget, err := generateBazelTarget(ctx, bin) + if err != nil { + return []BazelTarget{}, []error{err} + } + return []BazelTarget{binTarget}, nil +} + func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (conversionResults, []error) { buildFileToTargets := make(map[string]BazelTargets) @@ -262,6 +481,10 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers var errs []error + // Visit go libraries in a pre-run and store its state in a map + // The time complexity remains O(N), and this does not add significant wall time. + nameToGoLibMap := createGoLibraryModuleMap(ctx.Context()) + bpCtx := ctx.Context() bpCtx.VisitAllModules(func(m blueprint.Module) { dir := bpCtx.ModuleDir(m) @@ -269,6 +492,7 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers dirs[dir] = true var targets []BazelTarget + var targetErrs []error switch ctx.Mode() { case Bp2Build: @@ -317,7 +541,6 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers return } } - var targetErrs []error targets, targetErrs = generateBazelTargets(bpCtx, aModule) errs = append(errs, targetErrs...) for _, t := range targets { @@ -336,6 +559,14 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers metrics.AddUnconvertedModule(m, moduleType, dir, *reason) } return + } else if glib, ok := m.(*bootstrap.GoPackage); ok { + targets, targetErrs = generateBazelTargetsGoPackage(bpCtx, glib, nameToGoLibMap) + errs = append(errs, targetErrs...) + metrics.IncrementRuleClassCount("go_library") + } else if gbin, ok := m.(*bootstrap.GoBinary); ok { + targets, targetErrs = generateBazelTargetsGoBinary(bpCtx, gbin, nameToGoLibMap) + errs = append(errs, targetErrs...) + metrics.IncrementRuleClassCount("go_binary") } else { metrics.AddUnconvertedModule(m, moduleType, dir, android.UnconvertedReason{ ReasonType: int(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED), diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go index 18cb9e116..d9a786069 100644 --- a/bp2build/cc_binary_conversion_test.go +++ b/bp2build/cc_binary_conversion_test.go @@ -881,7 +881,7 @@ func TestCcBinaryWithSanitizerBlocklist(t *testing.T) { targets: []testBazelTarget{ {"cc_binary", "foo", AttrNameToString{ "local_includes": `["."]`, - "features": `["ubsan_blocklist_foo_blocklist_txt"]`, + "features": `["sanitizer_blocklist_foo_blocklist_txt"]`, }}, }, }) @@ -1214,3 +1214,82 @@ func TestCCBinaryRscriptSrc(t *testing.T) { }, }) } + +func TestCcBinaryStatic_SystemSharedLibUsedAsDep(t *testing.T) { + runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{ + description: "cc_library_static system_shared_lib empty for linux_bionic variant", + blueprint: soongCcLibraryStaticPreamble + + simpleModuleDoNotConvertBp2build("cc_library", "libc") + ` + +cc_library { + name: "libm", + bazel_module: { bp2build_available: false }, +} + +cc_binary { + name: "used_in_bionic_oses", + target: { + android: { + static_libs: ["libc"], + }, + linux_bionic: { + static_libs: ["libc"], + }, + }, + include_build_directory: false, + static_executable: true, +} + +cc_binary { + name: "all", + static_libs: ["libc"], + include_build_directory: false, + static_executable: true, +} + +cc_binary { + name: "keep_for_empty_system_shared_libs", + static_libs: ["libc"], + system_shared_libs: [], + include_build_directory: false, + static_executable: true, +} + +cc_binary { + name: "used_with_stubs", + static_libs: ["libm"], + include_build_directory: false, + static_executable: true, +} + +cc_binary { + name: "keep_with_stubs", + static_libs: ["libm"], + system_shared_libs: [], + include_build_directory: false, + static_executable: true, +} +`, + targets: []testBazelTarget{ + {"cc_binary", "all", AttrNameToString{ + "linkshared": "False", + }}, + {"cc_binary", "keep_for_empty_system_shared_libs", AttrNameToString{ + "deps": `[":libc_bp2build_cc_library_static"]`, + "system_deps": `[]`, + "linkshared": "False", + }}, + {"cc_binary", "keep_with_stubs", AttrNameToString{ + "linkshared": "False", + "deps": `[":libm_bp2build_cc_library_static"]`, + "system_deps": `[]`, + }}, + {"cc_binary", "used_in_bionic_oses", AttrNameToString{ + "linkshared": "False", + }}, + {"cc_binary", "used_with_stubs", AttrNameToString{ + "linkshared": "False", + }}, + }, + }) +} diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go index 1e3d72e6e..490cd91e8 100644 --- a/bp2build/cc_library_conversion_test.go +++ b/bp2build/cc_library_conversion_test.go @@ -4194,11 +4194,11 @@ cc_library { `, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{ - "features": `["ubsan_blocklist_foo_blocklist_txt"]`, + "features": `["sanitizer_blocklist_foo_blocklist_txt"]`, "local_includes": `["."]`, }), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{ - "features": `["ubsan_blocklist_foo_blocklist_txt"]`, + "features": `["sanitizer_blocklist_foo_blocklist_txt"]`, "local_includes": `["."]`, }), }, diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go index 2d61d5355..ccb426fa7 100644 --- a/bp2build/cc_library_shared_conversion_test.go +++ b/bp2build/cc_library_shared_conversion_test.go @@ -1225,7 +1225,7 @@ cc_library_shared { `, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{ - "features": `["ubsan_blocklist_foo_blocklist_txt"]`, + "features": `["sanitizer_blocklist_foo_blocklist_txt"]`, "local_includes": `["."]`, }), }, diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go index 18225dfa2..8084a5d8e 100644 --- a/bp2build/cc_library_static_conversion_test.go +++ b/bp2build/cc_library_static_conversion_test.go @@ -1918,7 +1918,7 @@ cc_library_static { `, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_static", "foo", AttrNameToString{ - "features": `["ubsan_blocklist_foo_blocklist_txt"]`, + "features": `["sanitizer_blocklist_foo_blocklist_txt"]`, "local_includes": `["."]`, }), }, diff --git a/bp2build/cc_test_conversion_test.go b/bp2build/cc_test_conversion_test.go index 4df4d4d46..20eb092d1 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"], @@ -115,7 +121,6 @@ cc_test_library { "//conditions:default": [], })`, "gtest": "True", - "isolated": "True", "local_includes": `["."]`, "dynamic_deps": `[":cc_test_lib2"] + select({ "//build/bazel/platforms/os:android": [":foolib"], @@ -152,7 +157,6 @@ cc_test { targets: []testBazelTarget{ {"cc_test", "mytest", AttrNameToString{ "gtest": "False", - "isolated": "False", "local_includes": `["."]`, "srcs": `["test.cpp"]`, }, @@ -171,14 +175,18 @@ 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 +205,19 @@ 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 +235,19 @@ 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 +266,14 @@ 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,8 +283,64 @@ 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{ + "gtest": "True", + "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{ + "gtest": "True", + "local_includes": `["."]`, + "srcs": `["test.cpp"]`, + "target_compatible_with": `["//build/bazel/platforms/os:android"]`, + "deps": `[":libgtest_isolated_main"]`, + "dynamic_deps": `[":liblog"]`, + }, + }, + }, + }) + } diff --git a/bp2build/go_conversion_test.go b/bp2build/go_conversion_test.go new file mode 100644 index 000000000..507fbf0ae --- /dev/null +++ b/bp2build/go_conversion_test.go @@ -0,0 +1,150 @@ +// Copyright 2023 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bp2build + +import ( + "testing" + + "github.com/google/blueprint/bootstrap" + + "android/soong/android" +) + +func runGoTests(t *testing.T, tc Bp2buildTestCase) { + RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) { + tCtx := ctx.(*android.TestContext) + bootstrap.RegisterGoModuleTypes(tCtx.Context.Context) // android.TestContext --> android.Context --> blueprint.Context + }, tc) +} + +func TestConvertGoPackage(t *testing.T) { + bp := ` +bootstrap_go_package { + name: "foo", + pkgPath: "android/foo", + deps: [ + "bar", + ], + srcs: [ + "foo1.go", + "foo2.go", + ], + linux: { + srcs: [ + "foo_linux.go", + ], + }, + darwin: { + srcs: [ + "foo_darwin.go", + ], + }, + testSrcs: [ + "foo1_test.go", + "foo2_test.go", + ], +} +` + depBp := ` +bootstrap_go_package { + name: "bar", +} +` + t.Parallel() + runGoTests(t, Bp2buildTestCase{ + Description: "Convert bootstrap_go_package to go_library", + ModuleTypeUnderTest: "bootrstap_go_package", + Blueprint: bp, + Filesystem: map[string]string{ + "bar/Android.bp": depBp, // Put dep in Android.bp to reduce boilerplate in ExpectedBazelTargets + }, + ExpectedBazelTargets: []string{makeBazelTargetHostOrDevice("go_library", "foo", + AttrNameToString{ + "deps": `["//bar:bar"]`, + "importpath": `"android/foo"`, + "srcs": `[ + "foo1.go", + "foo2.go", + ] + select({ + "//build/bazel/platforms/os:darwin": ["foo_darwin.go"], + "//build/bazel/platforms/os:linux_glibc": ["foo_linux.go"], + "//conditions:default": [], + })`, + }, + android.HostSupported, + )}, + }) +} + +func TestConvertGoBinaryWithTransitiveDeps(t *testing.T) { + bp := ` +blueprint_go_binary { + name: "foo", + srcs: ["main.go"], + deps: ["bar"], +} +` + depBp := ` +bootstrap_go_package { + name: "bar", + deps: ["baz"], +} +bootstrap_go_package { + name: "baz", +} +` + t.Parallel() + runGoTests(t, Bp2buildTestCase{ + Description: "Convert blueprint_go_binary to go_binary", + Blueprint: bp, + Filesystem: map[string]string{ + "bar/Android.bp": depBp, // Put dep in Android.bp to reduce boilerplate in ExpectedBazelTargets + }, + ExpectedBazelTargets: []string{makeBazelTargetHostOrDevice("go_binary", "foo", + AttrNameToString{ + "deps": `[ + "//bar:bar", + "//bar:baz", + ]`, + "srcs": `["main.go"]`, + }, + android.HostSupported, + )}, + }) +} + +func TestConvertGoBinaryWithSrcInDifferentPackage(t *testing.T) { + bp := ` +blueprint_go_binary { + name: "foo", + srcs: ["subdir/main.go"], +} +` + t.Parallel() + runGoTests(t, Bp2buildTestCase{ + Description: "Convert blueprint_go_binary with src in different package", + Blueprint: bp, + Filesystem: map[string]string{ + "subdir/Android.bp": "", + }, + ExpectedBazelTargets: []string{makeBazelTargetHostOrDevice("go_binary", "foo", + AttrNameToString{ + "deps": `[]`, + "srcs": `["//subdir:main.go"]`, + }, + android.HostSupported, + )}, + }) +} diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go index fd92e95c6..c501a7bcb 100644 --- a/bp2build/java_library_conversion_test.go +++ b/bp2build/java_library_conversion_test.go @@ -183,8 +183,8 @@ func TestJavaLibraryJavaVersion(t *testing.T) { }) } -func TestJavaLibraryErrorproneJavacflagsEnabledManually(t *testing.T) { - runJavaLibraryTestCase(t, Bp2buildTestCase{ +func TestJavaLibraryErrorproneEnabledManually(t *testing.T) { + runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{ Blueprint: `java_library { name: "java-lib-1", srcs: ["a.java"], @@ -192,7 +192,13 @@ func TestJavaLibraryErrorproneJavacflagsEnabledManually(t *testing.T) { errorprone: { enabled: true, javacflags: ["-Xep:SpeedLimit:OFF"], + extra_check_modules: ["plugin2"], }, +} +java_plugin { + name: "plugin2", + srcs: ["a.java"], + bazel_module: { bp2build_available: false }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{ @@ -200,10 +206,14 @@ func TestJavaLibraryErrorproneJavacflagsEnabledManually(t *testing.T) { "-Xsuper-fast", "-Xep:SpeedLimit:OFF", ]`, - "srcs": `["a.java"]`, + "plugins": `[":plugin2"]`, + "srcs": `["a.java"]`, + "errorprone_force_enable": `True`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), }, + }, func(ctx android.RegistrationContext) { + ctx.RegisterModuleType("java_plugin", java.PluginFactory) }) } @@ -227,21 +237,23 @@ func TestJavaLibraryErrorproneJavacflagsErrorproneDisabledByDefault(t *testing.T }) } -func TestJavaLibraryErrorproneJavacflagsErrorproneDisabledManually(t *testing.T) { +func TestJavaLibraryErrorproneDisabledManually(t *testing.T) { runJavaLibraryTestCase(t, Bp2buildTestCase{ Blueprint: `java_library { name: "java-lib-1", srcs: ["a.java"], javacflags: ["-Xsuper-fast"], errorprone: { - enabled: false, - javacflags: ["-Xep:SpeedLimit:OFF"], + enabled: false, }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{ - "javacopts": `["-Xsuper-fast"]`, - "srcs": `["a.java"]`, + "javacopts": `[ + "-Xsuper-fast", + "-XepDisableAllChecks", + ]`, + "srcs": `["a.java"]`, }), MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"), }, 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/build_kzip.bash b/build_kzip.bash index b1618616b..4c42048dd 100755 --- a/build_kzip.bash +++ b/build_kzip.bash @@ -44,7 +44,7 @@ kzip_targets=( # xref_rust ) -build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k "${kzip_targets[@]}" +build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k --skip-soong-tests --ninja_weight_source=not_used "${kzip_targets[@]}" # Build extraction file for Go the files in build/{blueprint,soong} directories. declare -r abspath_out=$(realpath "${out}") 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/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 5459595e2..9895a2043 100644 --- a/cc/bp2build.go +++ b/cc/bp2build.go @@ -43,6 +43,10 @@ const ( rScriptSrcPartition = "renderScript" + xsdSrcPartition = "xsd" + + hdrPartition = "hdr" + stubsSuffix = "_stub_libs_current" ) @@ -155,6 +159,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 +170,14 @@ 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)}, + 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 +416,8 @@ type compilerAttributes struct { srcs bazel.LabelListAttribute // xsd config sources - xsdInSrcs bazel.StringListAttribute + xsdSrcs bazel.LabelListAttribute + exportXsdSrcs bazel.LabelListAttribute // Lex sources and options lSrcs bazel.LabelListAttribute @@ -494,14 +508,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 +579,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 +593,19 @@ 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.srcs = partitionedSrcs[cppSrcPartition] ca.cSrcs = partitionedSrcs[cSrcPartition] ca.asSrcs = partitionedSrcs[asSrcPartition] @@ -604,11 +626,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 +642,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 +689,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 +733,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 +803,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 +822,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 +832,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 +848,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 +878,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 +895,14 @@ 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).wholeArchiveDeps.Append(compilerAttrs.exportXsdSrcs) + (&linkerAttrs).implementationWholeArchiveDeps.Append(compilerAttrs.xsdSrcs) + protoDep := bp2buildProto(ctx, module, compilerAttrs.protoSrcs) // bp2buildProto will only set wholeStaticLib or implementationWholeStaticLib, but we don't know @@ -1139,6 +1177,7 @@ type linkerAttributes struct { wholeArchiveDeps bazel.LabelListAttribute implementationWholeArchiveDeps bazel.LabelListAttribute systemDynamicDeps bazel.LabelListAttribute + usedSystemDynamicDepAsStaticDep map[string]bool usedSystemDynamicDepAsDynamicDep map[string]bool useVersionLib bazel.BoolAttribute @@ -1201,6 +1240,18 @@ func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversion // https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=247-249;drc=088b53577dde6e40085ffd737a1ae96ad82fc4b0 la.wholeArchiveDeps.SetSelectValue(axis, config, bazelLabelForWholeDepsExcludes(ctx, wholeStaticLibs, props.Exclude_static_libs)) + if isBinary && module.StaticExecutable() { + usedSystemStatic := android.FilterListPred(staticLibs, func(s string) bool { + return android.InList(s, soongSystemSharedLibs) && !android.InList(s, props.Exclude_static_libs) + }) + + for _, el := range usedSystemStatic { + if la.usedSystemDynamicDepAsStaticDep == nil { + la.usedSystemDynamicDepAsStaticDep = map[string]bool{} + } + la.usedSystemDynamicDepAsStaticDep[el] = true + } + } staticDeps := maybePartitionExportedAndImplementationsDepsExcludes( ctx, !isBinary, @@ -1233,6 +1284,7 @@ func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversion usedSystem := android.FilterListPred(sharedLibs, func(s string) bool { return android.InList(s, soongSystemSharedLibs) && !android.InList(s, excludeSharedLibs) }) + for _, el := range usedSystem { if la.usedSystemDynamicDepAsDynamicDep == nil { la.usedSystemDynamicDepAsDynamicDep = map[string]bool{} @@ -1625,6 +1677,15 @@ func (la *linkerAttributes) finalize(ctx android.BazelConversionPathContext) { } la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidPlatform, bazel.MakeLabelList(stubsToRemove)) } + if la.systemDynamicDeps.IsNil() && len(la.usedSystemDynamicDepAsStaticDep) > 0 { + toRemove := bazelLabelForStaticDeps(ctx, android.SortedKeys(la.usedSystemDynamicDepAsStaticDep)) + la.deps.Exclude(bazel.NoConfigAxis, "", toRemove) + la.deps.Exclude(bazel.OsConfigurationAxis, "android", toRemove) + la.deps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove) + la.implementationDeps.Exclude(bazel.NoConfigAxis, "", toRemove) + la.implementationDeps.Exclude(bazel.OsConfigurationAxis, "android", toRemove) + la.implementationDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove) + } la.deps.ResolveExcludes() la.implementationDeps.ResolveExcludes() @@ -1725,16 +1786,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 { @@ -1819,7 +1872,7 @@ func bp2buildSanitizerFeatures(ctx android.BazelConversionPathContext, m *Module if blocklist != nil { // Format the blocklist name to be used in a feature name blocklistFeatureSuffix := strings.Replace(strings.ToLower(*blocklist), ".", "_", -1) - features = append(features, "ubsan_blocklist_"+blocklistFeatureSuffix) + features = append(features, "sanitizer_blocklist_"+blocklistFeatureSuffix) } if sanitizerProps.Sanitize.Cfi != nil && !proptools.Bool(sanitizerProps.Sanitize.Cfi) { features = append(features, "-android_cfi") @@ -42,6 +42,7 @@ import ( func init() { RegisterCCBuildComponents(android.InitRegistrationContext) + pctx.Import("android/soong/android") pctx.Import("android/soong/cc/config") } @@ -568,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 { @@ -850,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 @@ -1079,6 +1099,10 @@ func (c *Module) CcLibraryInterface() bool { return false } +func (c *Module) RlibStd() bool { + panic(fmt.Errorf("RlibStd called on non-Rust module: %q", c.BaseModuleName())) +} + func (c *Module) RustLibraryInterface() bool { return false } @@ -1196,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()...) } @@ -1367,7 +1394,7 @@ func (c *Module) isPgoCompile() bool { func (c *Module) isCfi() bool { if sanitize := c.sanitize; sanitize != nil { - return Bool(sanitize.Properties.Sanitize.Cfi) + return Bool(sanitize.Properties.SanitizeMutated.Cfi) } return false } @@ -2144,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()) @@ -2158,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) } @@ -2215,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) @@ -2302,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) } @@ -2337,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) } @@ -2945,20 +3004,20 @@ func checkLinkType(ctx android.BaseModuleContext, from LinkableInterface, to Lin ctx.ModuleErrorf("links %q built against newer API version %q", ctx.OtherModuleName(to.Module()), "current") } else { - fromApi, err := strconv.Atoi(from.SdkVersion()) + fromApi, err := android.ApiLevelFromUserWithConfig(ctx.Config(), from.SdkVersion()) if err != nil { ctx.PropertyErrorf("sdk_version", - "Invalid sdk_version value (must be int or current): %q", + "Invalid sdk_version value (must be int, preview or current): %q", from.SdkVersion()) } - toApi, err := strconv.Atoi(to.SdkVersion()) + toApi, err := android.ApiLevelFromUserWithConfig(ctx.Config(), to.SdkVersion()) if err != nil { ctx.PropertyErrorf("sdk_version", - "Invalid sdk_version value (must be int or current): %q", + "Invalid sdk_version value (must be int, preview or current): %q", to.SdkVersion()) } - if toApi > fromApi { + if toApi.GreaterThan(fromApi) { ctx.ModuleErrorf("links %q built against newer API version %q", ctx.OtherModuleName(to.Module()), to.SdkVersion()) } diff --git a/cc/cc_test.go b/cc/cc_test.go index 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/config/global.go b/cc/config/global.go index ceab49801..ff5ab051e 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -48,7 +48,6 @@ var ( "-Wno-multichar", "-O2", - "-g", "-fdebug-default-version=5", "-fno-strict-aliasing", @@ -111,6 +110,9 @@ var ( // Turn off FMA which got enabled by default in clang-r445002 (http://b/218805949) "-ffp-contract=off", + + // Using simple template names reduces the size of debug builds. + "-gsimple-template-names", } commonGlobalConlyflags = []string{} @@ -375,6 +377,21 @@ func init() { flags = append(flags, "-Wno-error=unknown-warning-option") } + switch ctx.Config().Getenv("CLANG_DEFAULT_DEBUG_LEVEL") { + case "debug_level_0": + flags = append(flags, "-g0") + case "debug_level_1": + flags = append(flags, "-g1") + case "debug_level_2": + flags = append(flags, "-g2") + case "debug_level_3": + flags = append(flags, "-g3") + case "debug_level_g": + flags = append(flags, "-g") + default: + flags = append(flags, "-g") + } + return strings.Join(flags, " ") }) diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go index 3bc1e69c3..40919c0cf 100644 --- a/cc/config/riscv64_device.go +++ b/cc/config/riscv64_device.go @@ -26,9 +26,6 @@ var ( // Help catch common 32/64-bit errors. "-Werror=implicit-function-declaration", "-fno-emulated-tls", - // A temporary fix for SExtWRemoval miscompilation bug. - "-mllvm", - "-riscv-disable-sextw-removal=true", "-march=rv64gc_zba_zbb_zbs", } diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go index a0ef57595..62f75d1bd 100644 --- a/cc/config/toolchain.go +++ b/cc/config/toolchain.go @@ -261,5 +261,3 @@ func LibFuzzerRuntimeLibrary(t Toolchain) string { func LibFuzzerRuntimeInterceptors(t Toolchain) string { return LibclangRuntimeLibrary(t, "fuzzer_interceptors") } - -var inList = android.InList diff --git a/cc/fuzz.go b/cc/fuzz.go index 636ad855b..227fe8bcf 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -29,6 +29,7 @@ import ( func init() { android.RegisterModuleType("cc_fuzz", LibFuzzFactory) android.RegisterParallelSingletonType("cc_fuzz_packaging", fuzzPackagingFactory) + android.RegisterParallelSingletonType("cc_fuzz_presubmit_packaging", fuzzPackagingFactoryPresubmit) } type FuzzProperties struct { @@ -258,25 +259,29 @@ func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) { func PackageFuzzModule(ctx android.ModuleContext, fuzzPackagedModule fuzz.FuzzPackagedModule, pctx android.PackageContext) fuzz.FuzzPackagedModule { fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Corpus) - builder := android.NewRuleBuilder(pctx, ctx) intermediateDir := android.PathForModuleOut(ctx, "corpus") + + // Create one rule per file to avoid MAX_ARG_STRLEN hardlimit. for _, entry := range fuzzPackagedModule.Corpus { - builder.Command().Text("cp"). - Input(entry). - Output(intermediateDir.Join(ctx, entry.Base())) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Output: intermediateDir.Join(ctx, entry.Base()), + Input: entry, + }) } - builder.Build("copy_corpus", "copy corpus") fuzzPackagedModule.CorpusIntermediateDir = intermediateDir fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Data) - builder = android.NewRuleBuilder(pctx, ctx) intermediateDir = android.PathForModuleOut(ctx, "data") + + // Create one rule per file to avoid MAX_ARG_STRLEN hardlimit. for _, entry := range fuzzPackagedModule.Data { - builder.Command().Text("cp"). - Input(entry). - Output(intermediateDir.Join(ctx, entry.Rel())) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Output: intermediateDir.Join(ctx, entry.Rel()), + Input: entry, + }) } - builder.Build("copy_data", "copy data") fuzzPackagedModule.DataIntermediateDir = intermediateDir if fuzzPackagedModule.FuzzProperties.Dictionary != nil { @@ -352,9 +357,10 @@ func NewFuzzer(hod android.HostOrDeviceSupported) *Module { // their architecture & target/host specific zip file. type ccRustFuzzPackager struct { fuzz.FuzzPackager - fuzzPackagingArchModules string - fuzzTargetSharedDepsInstallPairs string - allFuzzTargetsName string + fuzzPackagingArchModules string + fuzzTargetSharedDepsInstallPairs string + allFuzzTargetsName string + onlyIncludePresubmits bool } func fuzzPackagingFactory() android.Singleton { @@ -363,6 +369,18 @@ func fuzzPackagingFactory() android.Singleton { fuzzPackagingArchModules: "SOONG_FUZZ_PACKAGING_ARCH_MODULES", fuzzTargetSharedDepsInstallPairs: "FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS", allFuzzTargetsName: "ALL_FUZZ_TARGETS", + onlyIncludePresubmits: false, + } + return fuzzPackager +} + +func fuzzPackagingFactoryPresubmit() android.Singleton { + + fuzzPackager := &ccRustFuzzPackager{ + fuzzPackagingArchModules: "SOONG_PRESUBMIT_FUZZ_PACKAGING_ARCH_MODULES", + fuzzTargetSharedDepsInstallPairs: "PRESUBMIT_FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS", + allFuzzTargetsName: "ALL_PRESUBMIT_FUZZ_TARGETS", + onlyIncludePresubmits: true, } return fuzzPackager } @@ -386,7 +404,6 @@ func (s *ccRustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) if !ok || ccModule.PreventInstall() { return } - // Discard non-fuzz targets. if ok := fuzz.IsValid(ccModule.FuzzModuleStruct()); !ok { return @@ -403,6 +420,9 @@ func (s *ccRustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) } else if ccModule.Host() { hostOrTargetString = "host" } + if s.onlyIncludePresubmits == true { + hostOrTargetString = "presubmit-" + hostOrTargetString + } fpm := fuzz.FuzzPackagedModule{} if ok { @@ -427,6 +447,14 @@ func (s *ccRustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) // The executable. files = append(files, fuzz.FileToZip{SourceFilePath: android.OutputFileForModule(ctx, ccModule, "unstripped")}) + if s.onlyIncludePresubmits == true { + if fpm.FuzzProperties.Fuzz_config == nil { + return + } + if !BoolDefault(fpm.FuzzProperties.Fuzz_config.Use_for_presubmit, false){ + return + } + } archDirs[archOs], ok = s.BuildZipFile(ctx, module, fpm, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs) if !ok { return diff --git a/cc/generated_cc_library.go b/cc/generated_cc_library.go new file mode 100644 index 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/library.go b/cc/library.go index aec6433d8..266fa7511 100644 --- a/cc/library.go +++ b/cc/library.go @@ -1963,6 +1963,10 @@ func (library *libraryDecorator) optInAbiDiff(ctx android.ModuleContext, referen libName := strings.TrimSuffix(baseName, filepath.Ext(baseName)) errorMessage := "error: Please update ABI references with: $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l " + libName + " -ref-dump-dir $$ANDROID_BUILD_TOP/" + refDumpDir + // Most opt-in libraries do not have dumps for all default architectures. + if ctx.Config().HasDeviceProduct() { + errorMessage += " -products " + ctx.Config().DeviceProduct() + } library.sourceAbiDiff(ctx, referenceDump, baseName, nameExt, isLlndkOrNdk, false /* allowExtensions */, "current", errorMessage) @@ -2271,7 +2275,7 @@ func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) { // do not install vndk libs // vndk libs are packaged into VNDK APEX - if ctx.isVndk() && !ctx.IsVndkExt() { + if ctx.isVndk() && !ctx.IsVndkExt() && !ctx.Config().IsVndkDeprecated() { return } } else if library.hasStubsVariants() && !ctx.Host() && ctx.directlyInAnyApex() { diff --git a/cc/linkable.go b/cc/linkable.go index 19e6501de..209939916 100644 --- a/cc/linkable.go +++ b/cc/linkable.go @@ -87,6 +87,12 @@ type Snapshottable interface { // SnapshotStaticLibs returns the list of static library dependencies for this module. SnapshotStaticLibs() []string + // SnapshotDylibs returns the list of dylib library dependencies for this module. + SnapshotDylibs() []string + + // SnapshotRlibs returns the list of rlib library dependencies for this module. + SnapshotRlibs() []string + // IsSnapshotPrebuilt returns true if this module is a snapshot prebuilt. IsSnapshotPrebuilt() bool } @@ -239,6 +245,9 @@ type LinkableInterface interface { // Dylib returns true if this is an dylib module. Dylib() bool + // RlibStd returns true if this is an rlib which links against an rlib libstd. + RlibStd() bool + // Static returns true if this is a static library module. Static() bool @@ -47,6 +47,7 @@ type LTOProperties struct { } `android:"arch_variant"` LtoEnabled bool `blueprint:"mutated"` + LtoDefault bool `blueprint:"mutated"` // Dep properties indicate that this module needs to be built with LTO // since it is an object dependency of an LTO module. @@ -66,7 +67,37 @@ func (lto *lto) props() []interface{} { } func (lto *lto) begin(ctx BaseModuleContext) { - lto.Properties.LtoEnabled = lto.LTO(ctx) + // First, determine the module indepedent default LTO mode. + ltoDefault := GlobalThinLTO(ctx) + if ctx.Config().IsEnvTrue("DISABLE_LTO") { + ltoDefault = false + } else if ctx.Host() { + // Performance and binary size are less important for host binaries. + ltoDefault = false + } else if ctx.Arch().ArchType.Multilib == "lib32" { + // LP32 has many subtle issues and less test coverage. + ltoDefault = false + } + + // Then, determine the actual LTO mode to use. If different from `ltoDefault`, a variant needs + // to be created. + ltoEnabled := ltoDefault + if lto.Never() { + ltoEnabled = false + } else if lto.ThinLTO() { + // Module explicitly requests for LTO. + ltoEnabled = true + } else if ctx.testBinary() || ctx.testLibrary() { + // Do not enable LTO for tests for better debugging. + ltoEnabled = false + } else if ctx.isVndk() { + // FIXME: ThinLTO for VNDK produces different output. + // b/169217596 + ltoEnabled = false + } + + lto.Properties.LtoDefault = ltoDefault + lto.Properties.LtoEnabled = ltoEnabled } func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags { @@ -80,7 +111,7 @@ func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags { var ltoLdFlags []string // The module did not explicitly turn on LTO. Only leverage LTO's - // better dead code elinmination and CFG simplification, but do + // better dead code elimination and CFG simplification, but do // not perform costly optimizations for a balance between compile // time, binary size and performance. if !lto.ThinLTO() { @@ -118,34 +149,6 @@ func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags { return flags } -// Determine which LTO mode to use for the given module. -func (lto *lto) LTO(ctx BaseModuleContext) bool { - if lto.Never() { - return false - } - if ctx.Config().IsEnvTrue("DISABLE_LTO") { - return false - } - // Module explicitly requests for LTO. - if lto.ThinLTO() { - return true - } - // LP32 has many subtle issues and less test coverage. - if ctx.Arch().ArchType.Multilib == "lib32" { - return false - } - // Performance and binary size are less important for host binaries and tests. - if ctx.Host() || ctx.testBinary() || ctx.testLibrary() { - return false - } - // FIXME: ThinLTO for VNDK produces different output. - // b/169217596 - if ctx.isVndk() { - return false - } - return GlobalThinLTO(ctx) -} - func (lto *lto) ThinLTO() bool { return lto != nil && proptools.Bool(lto.Properties.Lto.Thin) } @@ -155,15 +158,13 @@ func (lto *lto) Never() bool { } func GlobalThinLTO(ctx android.BaseModuleContext) bool { - return ctx.Config().IsEnvTrue("GLOBAL_THINLTO") + return !ctx.Config().IsEnvFalse("GLOBAL_THINLTO") } // Propagate lto requirements down from binaries func ltoDepsMutator(mctx android.TopDownMutatorContext) { - defaultLTOMode := GlobalThinLTO(mctx) - if m, ok := mctx.Module().(*Module); ok { - if m.lto == nil || m.lto.Properties.LtoEnabled == defaultLTOMode { + if m.lto == nil || m.lto.Properties.LtoEnabled == m.lto.Properties.LtoDefault { return } @@ -238,6 +239,7 @@ func ltoMutator(mctx android.BottomUpMutatorContext) { } variation.Properties.PreventInstall = true variation.Properties.HideFromMake = true + variation.lto.Properties.LtoDefault = m.lto.Properties.LtoDefault variation.lto.Properties.LtoDep = false variation.lto.Properties.NoLtoDep = false } diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go index 0cf21b65a..feb388037 100644 --- a/cc/ndk_sysroot.go +++ b/cc/ndk_sysroot.go @@ -58,7 +58,6 @@ import ( func init() { RegisterNdkModuleTypes(android.InitRegistrationContext) - pctx.Import("android/soong/android") } func RegisterNdkModuleTypes(ctx android.RegistrationContext) { diff --git a/cc/sanitize.go b/cc/sanitize.go index 62e31d1ca..626005b44 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -646,10 +646,6 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { if (ctx.Arch().ArchType != android.Arm64 && ctx.Arch().ArchType != android.Riscv64) || !ctx.toolchain().Bionic() { s.Scs = nil } - // ...but temporarily globally disabled on riscv64 (http://b/277909695). - if ctx.Arch().ArchType == android.Riscv64 { - s.Scs = nil - } // Memtag_heap is only implemented on AArch64. // Memtag ABI is Android specific for now, so disable for host. diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go index a5729dfc0..bb1331051 100644 --- a/cc/snapshot_prebuilt.go +++ b/cc/snapshot_prebuilt.go @@ -100,6 +100,7 @@ const ( snapshotBinarySuffix = "_binary." snapshotObjectSuffix = "_object." SnapshotRlibSuffix = "_rlib." + SnapshotDylibSuffix = "_dylib." ) type SnapshotProperties struct { @@ -107,6 +108,7 @@ type SnapshotProperties struct { Static_libs []string `android:"arch_variant"` Shared_libs []string `android:"arch_variant"` Rlibs []string `android:"arch_variant"` + Dylibs []string `android:"arch_variant"` Vndk_libs []string `android:"arch_variant"` Binaries []string `android:"arch_variant"` Objects []string `android:"arch_variant"` @@ -186,6 +188,7 @@ func (s *snapshotModule) DepsMutator(ctx android.BottomUpMutatorContext) { staticLibs := collectSnapshotMap(s.properties.Static_libs, snapshotSuffix, SnapshotStaticSuffix) sharedLibs := collectSnapshotMap(s.properties.Shared_libs, snapshotSuffix, SnapshotSharedSuffix) rlibs := collectSnapshotMap(s.properties.Rlibs, snapshotSuffix, SnapshotRlibSuffix) + dylibs := collectSnapshotMap(s.properties.Dylibs, snapshotSuffix, SnapshotDylibSuffix) vndkLibs := collectSnapshotMap(s.properties.Vndk_libs, "", vndkSuffix) for k, v := range vndkLibs { sharedLibs[k] = v @@ -198,11 +201,12 @@ func (s *snapshotModule) DepsMutator(ctx android.BottomUpMutatorContext) { StaticLibs: staticLibs, SharedLibs: sharedLibs, Rlibs: rlibs, + Dylibs: dylibs, }) } type SnapshotInfo struct { - HeaderLibs, Binaries, Objects, StaticLibs, SharedLibs, Rlibs map[string]string + HeaderLibs, Binaries, Objects, StaticLibs, SharedLibs, Rlibs, Dylibs map[string]string } var SnapshotInfoProvider = blueprint.NewMutatorProvider(SnapshotInfo{}, "deps") diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go index cf4617da3..1ee120eb8 100644 --- a/cc/snapshot_utils.go +++ b/cc/snapshot_utils.go @@ -57,6 +57,14 @@ func (m *Module) SnapshotStaticLibs() []string { return m.Properties.SnapshotStaticLibs } +func (m *Module) SnapshotRlibs() []string { + return []string{} +} + +func (m *Module) SnapshotDylibs() []string { + return []string{} +} + // snapshotLibraryInterface is an interface for libraries captured to VNDK / vendor snapshots. type snapshotLibraryInterface interface { libraryInterface @@ -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..53a097aba 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,14 +720,16 @@ func testBinaryBp2build(ctx android.TopDownMutatorContext, m *Module) { m.convertTidyAttributes(ctx, &testBinaryAttrs.tidyAttributes) + gtestIsolated := m.linker.(*testBinary).isolated(ctx) 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 } } + addImplicitGtestDeps(ctx, &testBinaryAttrs, gtestIsolated) + for _, testProps := range m.GetProperties() { if p, ok := testProps.(*TestBinaryProperties); ok { useVendor := false // TODO Bug: 262914724 @@ -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, 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 attrs.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/cc/util.go b/cc/util.go index 6d8ac435f..c93646b98 100644 --- a/cc/util.go +++ b/cc/util.go @@ -28,8 +28,8 @@ func includeDirsToFlags(dirs android.Paths) string { return android.JoinWithPrefix(dirs.Strings(), "-I") } -var indexList = android.IndexList -var inList = android.InList +var indexList = android.IndexList[string] +var inList = android.InList[string] var filterList = android.FilterList var removeListFromList = android.RemoveListFromList var removeFromList = android.RemoveFromList diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go index d2531c03d..9ea337b8d 100644 --- a/cc/vendor_snapshot.go +++ b/cc/vendor_snapshot.go @@ -108,10 +108,10 @@ func isSnapshotAware(cfg android.DeviceConfig, m LinkableInterface, inProprietar return false } } - if sanitizable.Static() { + if sanitizable.Static() || sanitizable.Rlib() { return sanitizable.OutputFile().Valid() && !isPrivate(image, m) } - if sanitizable.Shared() || sanitizable.Rlib() { + if sanitizable.Shared() || sanitizable.Dylib() { if !sanitizable.OutputFile().Valid() { return false } @@ -153,6 +153,8 @@ type snapshotJsonFlags struct { SharedLibs []string `json:",omitempty"` StaticLibs []string `json:",omitempty"` RuntimeLibs []string `json:",omitempty"` + Dylibs []string `json:",omitempty"` + Rlibs []string `json:",omitempty"` // extra config files InitRc []string `json:",omitempty"` @@ -283,8 +285,17 @@ var ccSnapshotAction snapshot.GenerateSnapshotAction = func(s snapshot.SnapshotS if m.Shared() { prop.SharedLibs = m.SnapshotSharedLibs() } - // static libs dependencies are required to collect the NOTICE files. + + // dylibs collect both shared and dylib dependencies. + if m.Dylib() { + prop.SharedLibs = m.SnapshotSharedLibs() + prop.Dylibs = m.SnapshotDylibs() + } + + // static and rlib libs dependencies are required to collect the NOTICE files. prop.StaticLibs = m.SnapshotStaticLibs() + prop.Rlibs = m.SnapshotRlibs() + if sanitizable, ok := m.(PlatformSanitizeable); ok { if sanitizable.Static() && sanitizable.SanitizePropDefined() { prop.SanitizeMinimalDep = sanitizable.MinimalRuntimeDep() || sanitizable.MinimalRuntimeNeeded() @@ -299,13 +310,15 @@ var ccSnapshotAction snapshot.GenerateSnapshotAction = func(s snapshot.SnapshotS libType = "shared" } else if m.Rlib() { libType = "rlib" + } else if m.Dylib() { + libType = "dylib" } else { libType = "header" } var stem string - // install .a or .so + // install .a, .rlib, .dylib.so, or .so if libType != "header" { libPath := m.OutputFile().Path() stem = libPath.Base() @@ -328,6 +341,12 @@ var ccSnapshotAction snapshot.GenerateSnapshotAction = func(s snapshot.SnapshotS } } } + if m.Rlib() && m.RlibStd() { + // rlibs produce both rlib-std and dylib-std variants + ext := filepath.Ext(stem) + stem = strings.TrimSuffix(stem, ext) + ".rlib-std" + ext + prop.ModuleName += ".rlib-std" + } snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, m.RelativeInstallPath(), stem) ret = append(ret, copyFile(ctx, libPath, snapshotLibOut, fake)) } else { @@ -341,8 +360,12 @@ var ccSnapshotAction snapshot.GenerateSnapshotAction = func(s snapshot.SnapshotS prop.StaticExecutable = m.StaticExecutable() prop.InstallInRoot = m.InstallInRoot() prop.SharedLibs = m.SnapshotSharedLibs() - // static libs dependencies are required to collect the NOTICE files. + prop.Dylibs = m.SnapshotDylibs() + + // static and rlib dependencies are required to collect the NOTICE files. prop.StaticLibs = m.SnapshotStaticLibs() + prop.Rlibs = m.SnapshotRlibs() + // install bin binPath := m.OutputFile().Path() snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base()) 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/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go index ba0648d19..3fb445480 100644 --- a/cmd/pom2bp/pom2bp.go +++ b/cmd/pom2bp/pom2bp.go @@ -556,7 +556,8 @@ var bpTemplate = template.Must(template.New("bp").Parse(` {{- end}} {{- end}} {{- if .IsApk}} - presigned: true + preprocessed: true, + presigned: true, {{- end}} } diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index 22d64a2ed..5ea84bcba 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -225,7 +225,7 @@ func runApiBp2build(ctx *android.Context, extraNinjaDeps []string) string { ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...) // Create soong_injection repository - soongInjectionFiles, err := bp2build.CreateSoongInjectionDirFiles(codegenContext, bp2build.CreateCodegenMetrics()) + soongInjectionFiles, workspaceFiles, err := bp2build.CreateSoongInjectionDirFiles(codegenContext, bp2build.CreateCodegenMetrics()) maybeQuit(err, "") absoluteSoongInjectionDir := shared.JoinPath(topDir, ctx.Config().SoongOutDir(), bazel.SoongInjectionDirName) for _, file := range soongInjectionFiles { @@ -236,6 +236,9 @@ func runApiBp2build(ctx *android.Context, extraNinjaDeps []string) string { // to allow users to edit/experiment in the synthetic workspace. writeReadWriteFile(absoluteSoongInjectionDir, file) } + for _, file := range workspaceFiles { + writeReadWriteFile(absoluteApiBp2buildDir, file) + } workspace := shared.JoinPath(ctx.Config().SoongOutDir(), "api_bp2build") // Create the symlink forest diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go index 682fb75c3..4097e8a3f 100644 --- a/cmd/soong_ui/main.go +++ b/cmd/soong_ui/main.go @@ -218,6 +218,11 @@ func main() { trace.SetOutput(filepath.Join(logsDir, c.logsPrefix+"build.trace")) + log.Verbose("Command Line: ") + for i, arg := range os.Args { + log.Verbosef(" [%d] %s", i, arg) + } + defer func() { stat.Finish() criticalPath.WriteToMetrics(met) diff --git a/cmd/zip2zip/BUILD.bazel b/cmd/zip2zip/BUILD.bazel deleted file mode 100644 index 1915a2dbf..000000000 --- a/cmd/zip2zip/BUILD.bazel +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (C) 2022 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -alias( - name = "zip2zip", - actual = "//prebuilts/build-tools:linux-x86/bin/zip2zip", -) diff --git a/dexpreopt/config.go b/dexpreopt/config.go index bb83dc842..ba41f4a66 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -45,7 +45,8 @@ type GlobalConfig struct { BootJars android.ConfiguredJarList // modules for jars that form the boot class path ApexBootJars android.ConfiguredJarList // jars within apex that form the boot class path - ArtApexJars android.ConfiguredJarList // modules for jars that are in the ART APEX + ArtApexJars android.ConfiguredJarList // modules for jars that are in the ART APEX + TestOnlyArtBootImageJars android.ConfiguredJarList // modules for jars to be included in the ART boot image for testing SystemServerJars android.ConfiguredJarList // system_server classpath jars on the platform SystemServerApps []string // apps that are loaded into system server @@ -700,6 +701,7 @@ func GlobalConfigForTests(ctx android.PathContext) *GlobalConfig { BootJars: android.EmptyConfiguredJarList(), ApexBootJars: android.EmptyConfiguredJarList(), ArtApexJars: android.EmptyConfiguredJarList(), + TestOnlyArtBootImageJars: android.EmptyConfiguredJarList(), SystemServerJars: android.EmptyConfiguredJarList(), SystemServerApps: nil, ApexSystemServerJars: android.EmptyConfiguredJarList(), diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go index 6ed0736f7..147a56231 100644 --- a/dexpreopt/testing.go +++ b/dexpreopt/testing.go @@ -111,6 +111,13 @@ func FixtureSetArtBootJars(bootJars ...string) android.FixturePreparer { }) } +// FixtureSetTestOnlyArtBootImageJars enables dexpreopt and sets the TestOnlyArtBootImageJars property. +func FixtureSetTestOnlyArtBootImageJars(bootJars ...string) android.FixturePreparer { + return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) { + dexpreoptConfig.TestOnlyArtBootImageJars = android.CreateTestConfiguredJarList(bootJars) + }) +} + // FixtureSetBootJars enables dexpreopt and sets the BootJars property. func FixtureSetBootJars(bootJars ...string) android.FixturePreparer { return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) { diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go index ada47128c..94b795f4d 100644 --- a/fuzz/fuzz_common.go +++ b/fuzz/fuzz_common.go @@ -371,6 +371,8 @@ type FuzzConfig struct { // Specifies whether fuzz target should check presubmitted code changes for crashes. // Defaults to false. Use_for_presubmit *bool `json:"use_for_presubmit,omitempty"` + // Specify which paths to exclude from fuzzing coverage reports + Exclude_paths_from_reports []string `json:"exclude_paths_from_reports,omitempty"` } type FuzzFrameworks struct { diff --git a/genrule/allowlists.go b/genrule/allowlists.go index 02b11450e..afa52cc7b 100644 --- a/genrule/allowlists.go +++ b/genrule/allowlists.go @@ -97,8 +97,6 @@ var ( "BlueberryFacadeGeneratedStub_cc", "BlueberryFacadeGeneratedStub_h", "BluetoothGeneratedDumpsysDataSchema_h", - "OpenwrtControlServerProto_cc", - "OpenwrtControlServerProto_h", "c2hal_test_genc++", "c2hal_test_genc++_headers", "hidl2aidl_test_gen_aidl", @@ -115,6 +113,28 @@ var ( "nos_app_weaver_service_genc++_headers", "nos_app_weaver_service_genc++_mock", "nos_generator_test_service_genc++", + "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 b29e2c96a..6306c2750 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -151,6 +151,9 @@ type generatorProperties struct { // input files to exclude Exclude_srcs []string `android:"path,arch_variant"` + + // Enable restat to update the output only if the output is changed + Write_if_changed *bool } type Module struct { @@ -293,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)) @@ -435,6 +441,7 @@ func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) { cmd = g.CmdModifier(ctx, cmd) } + var extraInputs android.Paths // Generate tasks, either from genrule or gensrcs. for i, task := range g.taskGenerator(ctx, cmd, srcFiles) { if len(task.out) == 0 { @@ -442,7 +449,6 @@ func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) { return } - var extraInputs android.Paths // Only handle extra inputs once as these currently are the same across all tasks if i == 0 { for name, values := range task.extraInputs { @@ -467,6 +473,9 @@ func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) { // Use a RuleBuilder to create a rule that runs the command inside an sbox sandbox. rule := getSandboxedRuleBuilder(ctx, android.NewRuleBuilder(pctx, ctx).Sbox(task.genDir, manifestPath)) + if Bool(g.properties.Write_if_changed) { + rule.Restat() + } cmd := rule.Command() for _, out := range task.out { diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go index 7c17db1be..7c14531bd 100644 --- a/genrule/genrule_test.go +++ b/genrule/genrule_test.go @@ -18,6 +18,7 @@ import ( "fmt" "os" "regexp" + "strconv" "testing" "android/soong/android" @@ -557,10 +558,12 @@ func TestGenSrcs(t *testing.T) { allowMissingDependencies bool - err string - cmds []string - deps []string - files []string + err string + cmds []string + deps []string + files []string + shards int + inputs []string }{ { name: "gensrcs", @@ -627,9 +630,29 @@ func TestGenSrcs(t *testing.T) { "out/soong/.intermediates/gen/gen/gensrcs/in2.h", "out/soong/.intermediates/gen/gen/gensrcs/in3.h", }, + shards: 2, + inputs: []string{ + "baz.txt", + }, }, } + checkInputs := func(t *testing.T, rule android.TestingBuildParams, inputs []string) { + t.Helper() + if len(inputs) == 0 { + return + } + inputBaseNames := map[string]bool{} + for _, f := range rule.Implicits { + inputBaseNames[f.Base()] = true + } + for _, f := range inputs { + if _, ok := inputBaseNames[f]; !ok { + t.Errorf("Expected to find input file %q for %q, but did not", f, rule.Description) + } + } + } + for _, test := range testcases { t.Run(test.name, func(t *testing.T) { bp := "gensrcs {\n" @@ -647,10 +670,21 @@ func TestGenSrcs(t *testing.T) { ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)). RunTestWithBp(t, testGenruleBp()+bp) + mod := result.ModuleForTests("gen", "") if expectedErrors != nil { return } + if test.shards > 0 { + for i := 0; i < test.shards; i++ { + r := mod.Rule("generator" + strconv.Itoa(i)) + checkInputs(t, r, test.inputs) + } + } else { + r := mod.Rule("generator") + checkInputs(t, r, test.inputs) + } + gen := result.Module("gen", "").(*Module) android.AssertDeepEquals(t, "cmd", test.cmds, gen.rawCommands) @@ -811,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/Android.bp b/java/Android.bp index e07986975..4450c4275 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -80,6 +80,7 @@ bootstrap_go_package { ], testSrcs: [ "aar_test.go", + "android_manifest_test.go", "androidmk_test.go", "app_import_test.go", "app_set_test.go", diff --git a/java/aar.go b/java/aar.go index 29e86e678..180e1d726 100644 --- a/java/aar.go +++ b/java/aar.go @@ -31,10 +31,9 @@ import ( type AndroidLibraryDependency interface { LibraryDependency ExportPackage() android.Path - ExportedRRODirs() []rroDir - ExportedStaticPackages() android.Paths - ExportedManifests() android.Paths - ExportedAssets() android.OptionalPath + ResourcesNodeDepSet() *android.DepSet[*resourcesNode] + RRODirsDepSet() *android.DepSet[rroDir] + ManifestsDepSet() *android.DepSet[android.Path] SetRROEnforcedForDependent(enforce bool) IsRROEnforced(ctx android.BaseModuleContext) bool } @@ -89,35 +88,49 @@ 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 - transitiveManifestPaths android.Paths - proguardOptionsFile android.Path - rroDirs []rroDir - 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 aaptProperties aaptProperties + + resourcesNodesDepSet *android.DepSet[*resourcesNode] + rroDirsDepSet *android.DepSet[rroDir] + manifestsDepSet *android.DepSet[android.Path] } type split struct { @@ -138,20 +151,23 @@ 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 } - -func (a *aapt) ExportedRRODirs() []rroDir { - return a.rroDirs +func (a *aapt) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] { + return a.resourcesNodesDepSet } -func (a *aapt) ExportedManifests() android.Paths { - return a.transitiveManifestPaths +func (a *aapt) RRODirsDepSet() *android.DepSet[rroDir] { + return a.rroDirsDepSet } -func (a *aapt) ExportedAssets() android.OptionalPath { - return a.assetPackage +func (a *aapt) ManifestsDepSet() *android.DepSet[android.Path] { + return a.manifestsDepSet } func (a *aapt) SetRROEnforcedForDependent(enforce bool) { @@ -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") @@ -291,7 +305,7 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon classLoaderContexts dexpreopt.ClassLoaderContextMap, excludedLibs []string, enforceDefaultTargetSdkVersion bool, extraLinkFlags ...string) { - transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags := + staticResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedDeps, libFlags := aaptLibs(ctx, sdkContext, classLoaderContexts) // Exclude any libraries from the supplied list. @@ -314,13 +328,20 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon EnforceDefaultTargetSdkVersion: enforceDefaultTargetSdkVersion, }) + staticDeps := transitiveAarDeps(staticResourcesNodesDepSet.ToList()) + // Add additional manifest files to transitive manifests. additionalManifests := android.PathsForModuleSrc(ctx, a.aaptProperties.Additional_manifests) - a.transitiveManifestPaths = append(android.Paths{manifestPath}, additionalManifests...) - a.transitiveManifestPaths = append(a.transitiveManifestPaths, transitiveStaticLibManifests...) - - if len(a.transitiveManifestPaths) > 1 && !Bool(a.aaptProperties.Dont_merge_manifests) { - a.mergedManifestFile = manifestMerger(ctx, a.transitiveManifestPaths[0], a.transitiveManifestPaths[1:], a.isLibrary) + transitiveManifestPaths := append(android.Paths{manifestPath}, additionalManifests...) + // TODO(b/288358614): Soong has historically not merged manifests from dependencies of android_library_import + // modules. Merging manifests from dependencies could remove the need for pom2bp to generate the "-nodeps" copies + // of androidx libraries, but doing so triggers errors due to errors introduced by existing dependencies of + // android_library_import modules. If this is fixed, staticManifestsDepSet can be dropped completely in favor of + // staticResourcesNodesDepSet.manifests() + transitiveManifestPaths = append(transitiveManifestPaths, staticManifestsDepSet.ToList()...) + + if len(transitiveManifestPaths) > 1 && !Bool(a.aaptProperties.Dont_merge_manifests) { + a.mergedManifestFile = manifestMerger(ctx, transitiveManifestPaths[0], transitiveManifestPaths[1:], a.isLibrary) if !a.isLibrary { // Only use the merged manifest for applications. For libraries, the transitive closure of manifests // will be propagated to the final application and merged there. The merged manifest for libraries is @@ -333,14 +354,27 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, sdkContext, manifestPath) - rroDirs = append(rroDirs, staticRRODirs...) linkFlags = append(linkFlags, libFlags...) - linkDeps = append(linkDeps, libDeps...) + linkDeps = append(linkDeps, sharedDeps...) + linkDeps = append(linkDeps, staticDeps.resPackages()...) linkFlags = append(linkFlags, extraLinkFlags...) if a.isLibrary { 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") @@ -348,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 { @@ -363,7 +398,27 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon var compiledRes, compiledOverlay android.Paths - compiledOverlay = append(compiledOverlay, transitiveStaticLibs...) + // AAPT2 overlays are in lowest to highest priority order, reverse the topological order + // of transitiveStaticLibs. + transitiveStaticLibs := android.ReversePaths(staticDeps.resPackages()) + + 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. @@ -404,12 +459,18 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon }) } + // No need to specify assets from dependencies to aapt2Link for libraries, all transitive assets will be + // provided to the final app aapt2Link step. + var transitiveAssets android.Paths + if !a.isLibrary { + transitiveAssets = android.ReverseSliceInPlace(staticDeps.assets()) + } aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt, extraPackages, - linkFlags, linkDeps, compiledRes, compiledOverlay, assetPackages, splitPackages) + linkFlags, linkDeps, compiledRes, compiledOverlay, transitiveAssets, splitPackages) // Extract assets from the resource package output so that they can be used later in aapt2link // for modules that depend on this one. - if android.PrefixInList(linkFlags, "-A ") || len(assetPackages) > 0 { + if android.PrefixInList(linkFlags, "-A ") { assets := android.PathForModuleOut(ctx, "assets.zip") ctx.Build(pctx, android.BuildParams{ Rule: extractAssetsRule, @@ -420,21 +481,142 @@ 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 - a.rroDirs = rroDirs a.extraAaptPackagesFile = extraPackages a.rTxt = rTxt a.splits = splits + a.resourcesNodesDepSet = android.NewDepSetBuilder[*resourcesNode](android.TOPOLOGICAL). + Direct(&resourcesNode{ + 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). + Direct(rroDirs...). + Transitive(staticRRODirsDepSet).Build() + a.manifestsDepSet = android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL). + Direct(a.manifestPath). + DirectSlice(additionalManifests). + 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 { + paths := make(android.Paths, 0, len(t)) + for _, dep := range t { + paths = append(paths, dep.resPackage) + } + return paths +} + +func (t transitiveAarDeps) manifests() android.Paths { + paths := make(android.Paths, 0, len(t)) + for _, dep := range t { + paths = append(paths, dep.manifest) + paths = append(paths, dep.additionalManifests...) + } + 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 { + paths := make(android.Paths, 0, len(t)) + for _, dep := range t { + if dep.assets.Valid() { + paths = append(paths, dep.assets.Path()) + } + } + return paths } // aaptLibs collects libraries from dependencies and sdk_version and converts them into paths func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap) ( - transitiveStaticLibs, transitiveStaticLibManifests android.Paths, staticRRODirs []rroDir, assets, deps android.Paths, flags []string) { - - var sharedLibs android.Paths + staticResourcesNodes *android.DepSet[*resourcesNode], staticRRODirs *android.DepSet[rroDir], + staticManifests *android.DepSet[android.Path], sharedLibs android.Paths, flags []string) { if classLoaderContexts == nil { // Not all callers need to compute class loader context, those who don't just pass nil. @@ -447,6 +629,10 @@ func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, classLoa sharedLibs = append(sharedLibs, sdkDep.jars...) } + var resourcesNodeDepSets []*android.DepSet[*resourcesNode] + rroDirsDepSetBuilder := android.NewDepSetBuilder[rroDir](android.TOPOLOGICAL) + manifestsDepSetBuilder := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL) + ctx.VisitDirectDeps(func(module android.Module) { depTag := ctx.OtherModuleDependencyTag(module) @@ -469,32 +655,28 @@ func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, classLoa } case staticLibTag: if exportPackage != nil { - transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...) - transitiveStaticLibs = append(transitiveStaticLibs, exportPackage) - transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...) - if aarDep.ExportedAssets().Valid() { - assets = append(assets, aarDep.ExportedAssets().Path()) - } - - outer: - for _, d := range aarDep.ExportedRRODirs() { - for _, e := range staticRRODirs { - if d.path == e.path { - continue outer - } - } - staticRRODirs = append(staticRRODirs, d) - } + resourcesNodeDepSets = append(resourcesNodeDepSets, aarDep.ResourcesNodeDepSet()) + rroDirsDepSetBuilder.Transitive(aarDep.RRODirsDepSet()) + manifestsDepSetBuilder.Transitive(aarDep.ManifestsDepSet()) } } addCLCFromDep(ctx, module, classLoaderContexts) }) - deps = append(deps, sharedLibs...) - deps = append(deps, transitiveStaticLibs...) + // AAPT2 overlays are in lowest to highest priority order, the topological order will be reversed later. + // Reverse the dependency order now going into the depset so that it comes out in order after the second + // reverse later. + // NOTE: this is legacy and probably incorrect behavior, for most other cases (e.g. conflicting classes in + // dependencies) the highest priority dependency is listed first, but for resources the highest priority + // dependency has to be listed last. + staticResourcesNodes = android.NewDepSet(android.TOPOLOGICAL, nil, + android.ReverseSliceInPlace(resourcesNodeDepSets)) - if len(transitiveStaticLibs) > 0 { + staticRRODirs = rroDirsDepSetBuilder.Build() + staticManifests = manifestsDepSetBuilder.Build() + + if len(staticResourcesNodes.ToList()) > 0 { flags = append(flags, "--auto-add-overlay") } @@ -502,10 +684,7 @@ func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, classLoa flags = append(flags, "-I "+sharedLib.String()) } - transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs) - transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests) - - return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assets, deps, flags + return staticResourcesNodes, staticRRODirs, staticManifests, sharedLibs, flags } type AndroidLibrary struct { @@ -516,8 +695,6 @@ type AndroidLibrary struct { androidLibraryProperties androidLibraryProperties aarFile android.WritablePath - - exportedStaticPackages android.Paths } var _ android.OutputFileProducer = (*AndroidLibrary)(nil) @@ -532,10 +709,6 @@ func (a *AndroidLibrary) OutputFiles(tag string) (android.Paths, error) { } } -func (a *AndroidLibrary) ExportedStaticPackages() android.Paths { - return a.exportedStaticPackages -} - var _ AndroidLibraryDependency = (*AndroidLibrary)(nil) func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { @@ -554,9 +727,14 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() - ctx.CheckbuildFile(a.proguardOptionsFile) - ctx.CheckbuildFile(a.exportPackage) - ctx.CheckbuildFile(a.aaptSrcJar) + a.stem = proptools.StringDefault(a.overridableDeviceProperties.Stem, ctx.ModuleName()) + + ctx.CheckbuildFile(a.aapt.proguardOptionsFile) + ctx.CheckbuildFile(a.aapt.exportPackage) + ctx.CheckbuildFile(a.aapt.aaptSrcJar) + if a.useResourceProcessorBusyBox() { + ctx.CheckbuildFile(a.aapt.rJar) + } // apps manifests are handled by aapt, don't let Module see them a.properties.Manifest = nil @@ -568,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 @@ -579,19 +772,15 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles, android.PathsForModuleSrc(ctx, a.dexProperties.Optimize.Proguard_flags_files)...) + ctx.VisitDirectDeps(func(m android.Module) { if ctx.OtherModuleDependencyTag(m) == staticLibTag { if lib, ok := m.(LibraryDependency); ok { a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles, lib.ExportedProguardFlagFiles()...) } - if alib, ok := m.(AndroidLibraryDependency); ok { - a.exportedStaticPackages = append(a.exportedStaticPackages, alib.ExportPackage()) - a.exportedStaticPackages = append(a.exportedStaticPackages, alib.ExportedStaticPackages()...) - } } }) a.exportedProguardFlagFiles = android.FirstUniquePaths(a.exportedProguardFlagFiles) - a.exportedStaticPackages = android.FirstUniquePaths(a.exportedStaticPackages) prebuiltJniPackages := android.Paths{} ctx.VisitDirectDeps(func(module android.Module) { @@ -674,14 +863,18 @@ 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 - exportedStaticPackages android.Paths + resourcesNodesDepSet *android.DepSet[*resourcesNode] + manifestsDepSet *android.DepSet[android.Path] hideApexVariantFromMake bool @@ -738,25 +931,20 @@ var _ AndroidLibraryDependency = (*AARImport)(nil) func (a *AARImport) ExportPackage() android.Path { return a.exportPackage } - func (a *AARImport) ExportedProguardFlagFiles() android.Paths { return android.Paths{a.proguardFlags} } -func (a *AARImport) ExportedRRODirs() []rroDir { - return nil -} - -func (a *AARImport) ExportedStaticPackages() android.Paths { - return a.exportedStaticPackages +func (a *AARImport) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] { + return a.resourcesNodesDepSet } -func (a *AARImport) ExportedManifests() android.Paths { - return android.Paths{a.manifest} +func (a *AARImport) RRODirsDepSet() *android.DepSet[rroDir] { + return android.NewDepSet[rroDir](android.TOPOLOGICAL, nil, nil) } -func (a *AARImport) ExportedAssets() android.OptionalPath { - return android.OptionalPathForPath(a.assetsPackage) +func (a *AARImport) ManifestsDepSet() *android.DepSet[android.Path] { + return a.manifestsDepSet } // RRO enforcement is not available on aar_import since its RRO dirs are not @@ -852,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(), @@ -877,46 +1066,70 @@ 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", } linkFlags = append(linkFlags, "--manifest "+a.manifest.String()) linkDeps = append(linkDeps, a.manifest) - transitiveStaticLibs, staticLibManifests, staticRRODirs, transitiveAssets, libDeps, libFlags := + staticResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedLibs, libFlags := aaptLibs(ctx, android.SdkContext(a), nil) - _ = staticLibManifests - _ = staticRRODirs + _ = staticRRODirsDepSet + staticDeps := transitiveAarDeps(staticResourcesNodesDepSet.ToList()) - linkDeps = append(linkDeps, libDeps...) + linkDeps = append(linkDeps, sharedLibs...) + linkDeps = append(linkDeps, staticDeps.resPackages()...) linkFlags = append(linkFlags, libFlags...) - overlayRes := append(android.Paths{flata}, transitiveStaticLibs...) + overlayRes := android.Paths{flata} - aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile, + // 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, a.rTxt, a.extraAaptPackagesFile, linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil) - // Merge this import's assets with its dependencies' assets (if there are any). - if len(transitiveAssets) > 0 { - mergedAssets := android.PathForModuleOut(ctx, "merged-assets.zip") - inputZips := append(android.Paths{a.assetsPackage}, transitiveAssets...) - ctx.Build(pctx, android.BuildParams{ - Rule: mergeAssetsRule, - Inputs: inputZips, - Output: mergedAssets, - Description: "merge assets from dependencies and self", - }) - a.assetsPackage = mergedAssets - } + 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() + + manifestDepSetBuilder := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(a.manifest) + // TODO(b/288358614): Soong has historically not merged manifests from dependencies of android_library_import + // modules. Merging manifests from dependencies could remove the need for pom2bp to generate the "-nodeps" copies + // of androidx libraries, but doing so triggers errors due to errors introduced by existing dependencies of + // android_library_import modules. If this is fixed, AndroidLibraryDependency.ManifestsDepSet can be dropped + // completely in favor of AndroidLibraryDependency.ResourceNodesDepSet.manifest + //manifestDepSetBuilder.Transitive(transitiveStaticDeps.manifests) + _ = staticManifestsDepSet + a.manifestsDepSet = manifestDepSetBuilder.Build() + + a.transitiveAaptResourcePackages = staticDeps.resPackages() a.collectTransitiveHeaderJars(ctx) ctx.SetProvider(JavaInfoProvider, JavaInfo{ @@ -925,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/android_manifest_test.go b/java/android_manifest_test.go new file mode 100644 index 000000000..b12d77896 --- /dev/null +++ b/java/android_manifest_test.go @@ -0,0 +1,103 @@ +// 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 java + +import ( + "android/soong/android" + "testing" +) + +func TestManifestMerger(t *testing.T) { + bp := ` + android_app { + name: "app", + sdk_version: "current", + srcs: ["app/app.java"], + resource_dirs: ["app/res"], + manifest: "app/AndroidManifest.xml", + additional_manifests: ["app/AndroidManifest2.xml"], + static_libs: ["direct", "direct_import"], + } + + android_library { + name: "direct", + sdk_version: "current", + srcs: ["direct/direct.java"], + resource_dirs: ["direct/res"], + manifest: "direct/AndroidManifest.xml", + additional_manifests: ["direct/AndroidManifest2.xml"], + static_libs: ["transitive", "transitive_import"], + } + + android_library { + name: "transitive", + sdk_version: "current", + srcs: ["transitive/transitive.java"], + resource_dirs: ["transitive/res"], + manifest: "transitive/AndroidManifest.xml", + additional_manifests: ["transitive/AndroidManifest2.xml"], + } + + android_library_import { + name: "direct_import", + sdk_version: "current", + aars: ["direct_import.aar"], + static_libs: ["direct_import_dep"], + } + + android_library_import { + name: "direct_import_dep", + sdk_version: "current", + aars: ["direct_import_dep.aar"], + } + + android_library_import { + name: "transitive_import", + sdk_version: "current", + aars: ["transitive_import.aar"], + static_libs: ["transitive_import_dep"], + } + + android_library_import { + name: "transitive_import_dep", + sdk_version: "current", + aars: ["transitive_import_dep.aar"], + } + ` + + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + PrepareForTestWithOverlayBuildComponents, + ).RunTestWithBp(t, bp) + + manifestMergerRule := result.ModuleForTests("app", "android_common").Rule("manifestMerger") + android.AssertPathRelativeToTopEquals(t, "main manifest", + "out/soong/.intermediates/app/android_common/manifest_fixer/AndroidManifest.xml", + manifestMergerRule.Input) + android.AssertPathsRelativeToTopEquals(t, "lib manifests", + []string{ + "app/AndroidManifest2.xml", + "out/soong/.intermediates/direct/android_common/manifest_fixer/AndroidManifest.xml", + "direct/AndroidManifest2.xml", + "out/soong/.intermediates/transitive/android_common/manifest_fixer/AndroidManifest.xml", + "transitive/AndroidManifest2.xml", + "out/soong/.intermediates/transitive_import/android_common/aar/AndroidManifest.xml", + "out/soong/.intermediates/direct_import/android_common/aar/AndroidManifest.xml", + // TODO(b/288358614): Soong has historically not merged manifests from dependencies of + // android_library_import modules. + + }, + manifestMergerRule.Implicits) +} diff --git a/java/androidmk.go b/java/androidmk.go index 9c21633fb..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()) @@ -368,8 +378,13 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { filterRRO := func(filter overlayType) android.Paths { var paths android.Paths - for _, d := range app.rroDirs { + seen := make(map[android.Path]bool) + for _, d := range app.rroDirsDepSet.ToList() { if d.overlayType == filter { + if seen[d.path] { + continue + } + seen[d.path] = true paths = append(paths, d.path) } } @@ -432,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{ @@ -450,11 +469,6 @@ func (a *AndroidApp) getOverriddenPackages() []string { if len(a.overridableAppProperties.Overrides) > 0 { overridden = append(overridden, a.overridableAppProperties.Overrides...) } - // When APK name is overridden via PRODUCT_PACKAGE_NAME_OVERRIDES - // ensure that the original name is overridden. - if a.Stem() != a.installApkName { - overridden = append(overridden, a.Stem()) - } return overridden } @@ -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 d9272e4fc..224bc8867 100755 --- a/java/app.go +++ b/java/app.go @@ -204,8 +204,8 @@ func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths { return nil } -func (a *AndroidApp) ExportedStaticPackages() android.Paths { - return nil +func (a *AndroidApp) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] { + return a.aapt.resourcesNodesDepSet } func (a *AndroidApp) OutputFile() android.Path { @@ -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() @@ -666,8 +682,17 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx) a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex) + // Unlike installApkName, a.stem should respect base module name for override_android_app. + // Therefore, use ctx.ModuleName() instead of a.Name(). + a.stem = proptools.StringDefault(a.overridableDeviceProperties.Stem, ctx.ModuleName()) + // Check if the install APK name needs to be overridden. - a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(a.Stem()) + // Both android_app and override_android_app module are expected to possess + // its module bound apk path. However, override_android_app inherits ctx.ModuleName() + // from the base module. Therefore, use a.Name() which represents + // the module name for both android_app and override_android_app. + a.installApkName = ctx.DeviceConfig().OverridePackageNameFor( + proptools.StringDefault(a.overridableDeviceProperties.Stem, a.Name())) if ctx.ModuleName() == "framework-res" { // framework-res.apk is installed as system/framework/framework-res.apk @@ -1571,7 +1596,9 @@ func androidAppCertificateBp2Build(ctx android.TopDownMutatorContext, module *An } type manifestValueAttribute struct { - MinSdkVersion *string + MinSdkVersion *string + MaxSdkVersion *string + TargetSdkVersion *string } type bazelAndroidAppAttributes struct { @@ -1601,12 +1628,25 @@ func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) { // MinSdkVersion(ctx) calls SdkVersion(ctx) if no value for min_sdk_version is set minSdkVersion := a.MinSdkVersion(ctx) if !minSdkVersion.IsPreview() && !minSdkVersion.IsInvalid() { - minSdkStr, err := minSdkVersion.EffectiveVersionString(ctx) - if err == nil { + if minSdkStr, err := minSdkVersion.EffectiveVersionString(ctx); err == nil { manifestValues.MinSdkVersion = &minSdkStr } } + maxSdkVersion := a.MaxSdkVersion(ctx) + if !maxSdkVersion.IsPreview() && !maxSdkVersion.IsInvalid() { + if maxSdkStr, err := maxSdkVersion.EffectiveVersionString(ctx); err == nil { + manifestValues.MaxSdkVersion = &maxSdkStr + } + } + + targetSdkVersion := a.TargetSdkVersion(ctx) + if !targetSdkVersion.IsPreview() && !targetSdkVersion.IsInvalid() { + if targetSdkStr, err := targetSdkVersion.EffectiveVersionString(ctx); err == nil { + manifestValues.TargetSdkVersion = &targetSdkStr + } + } + appAttrs := &bazelAndroidAppAttributes{ // TODO(b/209576404): handle package name override by product variable PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES Custom_package: a.overridableAppProperties.Package_name, diff --git a/java/app_import.go b/java/app_import.go index 842721728..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) { @@ -335,11 +346,19 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext // Sign or align the package if package has not been preprocessed if proptools.Bool(a.properties.Preprocessed) { - output := srcApk + var output android.WritablePath if !proptools.Bool(a.properties.Skip_preprocessed_apk_checks) { - writableOutput := android.PathForModuleOut(ctx, "validated-prebuilt", apkFilename) - a.validatePreprocessedApk(ctx, srcApk, writableOutput) - output = writableOutput + output = android.PathForModuleOut(ctx, "validated-prebuilt", apkFilename) + a.validatePreprocessedApk(ctx, srcApk, output) + } else { + // If using the input APK unmodified, still make a copy of it so that the output filename has the + // right basename. + output = android.PathForModuleOut(ctx, apkFilename) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: srcApk, + Output: output, + }) } a.outputFile = output a.certificate = PresignedCertificate @@ -376,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 0f98416d2..4627ff6fc 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -599,7 +599,7 @@ func TestLibraryAssets(t *testing.T) { android_library { name: "lib3", sdk_version: "current", - static_libs: ["lib4"], + static_libs: ["lib4", "import"], } android_library { @@ -607,6 +607,12 @@ func TestLibraryAssets(t *testing.T) { sdk_version: "current", asset_dirs: ["assets_b"], } + + android_library_import { + name: "import", + sdk_version: "current", + aars: ["import.aar"], + } ` testCases := []struct { @@ -616,11 +622,12 @@ func TestLibraryAssets(t *testing.T) { }{ { name: "foo", - // lib1 has its own asset. lib3 doesn't have any, but provides lib4's transitively. + // lib1 has its own assets. lib3 doesn't have any, but lib4 and import have assets. assetPackages: []string{ "out/soong/.intermediates/foo/android_common/aapt2/package-res.apk", "out/soong/.intermediates/lib1/android_common/assets.zip", - "out/soong/.intermediates/lib3/android_common/assets.zip", + "out/soong/.intermediates/lib4/android_common/assets.zip", + "out/soong/.intermediates/import/android_common/assets.zip", }, }, { @@ -632,10 +639,6 @@ func TestLibraryAssets(t *testing.T) { }, { name: "lib3", - assetPackages: []string{ - "out/soong/.intermediates/lib3/android_common/aapt2/package-res.apk", - "out/soong/.intermediates/lib4/android_common/assets.zip", - }, }, { name: "lib4", @@ -717,7 +720,514 @@ func TestAppJavaResources(t *testing.T) { } } -func TestAndroidResources(t *testing.T) { +func TestAndroidResourceProcessor(t *testing.T) { + testCases := []struct { + name string + appUsesRP bool + directLibUsesRP bool + transitiveLibUsesRP bool + + dontVerifyApp bool + appResources []string + appOverlays []string + appImports []string + appSrcJars []string + appClasspath []string + appCombined []string + + dontVerifyDirect bool + directResources []string + directOverlays []string + directImports []string + directSrcJars []string + directClasspath []string + directCombined []string + + dontVerifyTransitive bool + transitiveResources []string + transitiveOverlays []string + transitiveImports []string + transitiveSrcJars []string + transitiveClasspath []string + transitiveCombined []string + + dontVerifyDirectImport bool + directImportResources []string + directImportOverlays []string + directImportImports []string + + dontVerifyTransitiveImport bool + transitiveImportResources []string + transitiveImportOverlays []string + transitiveImportImports []string + }{ + { + // 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{ + "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: []string{"out/soong/.intermediates/transitive/android_common/gen/android/R.srcjar"}, + transitiveClasspath: []string{"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.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 with all modules set to use_resource_processor: true. + name: "resource_processor", + appUsesRP: true, + directLibUsesRP: true, + transitiveLibUsesRP: true, + + appResources: nil, + appOverlays: []string{ + "out/soong/.intermediates/transitive/android_common/package-res.apk", + "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", + "out/soong/.intermediates/transitive_import/android_common/package-res.apk", + "out/soong/.intermediates/direct/android_common/package-res.apk", + "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk", + "out/soong/.intermediates/direct_import/android_common/package-res.apk", + "out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat", + }, + appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"}, + appSrcJars: nil, + appClasspath: []string{ + "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", + "out/soong/.intermediates/app/android_common/busybox/R.jar", + "out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar", + "out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar", + }, + appCombined: []string{ + "out/soong/.intermediates/app/android_common/busybox/R.jar", + "out/soong/.intermediates/app/android_common/javac/app.jar", + "out/soong/.intermediates/direct/android_common/combined/direct.jar", + "out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar", + }, + + directResources: nil, + directOverlays: []string{"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat"}, + directImports: []string{ + "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", + "out/soong/.intermediates/transitive_import/android_common/package-res.apk", + "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", + "out/soong/.intermediates/transitive/android_common/package-res.apk", + }, + directSrcJars: nil, + directClasspath: []string{ + "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", + "out/soong/.intermediates/transitive_import/android_common/busybox/R.jar", + "out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar", + "out/soong/.intermediates/transitive/android_common/busybox/R.jar", + "out/soong/.intermediates/direct/android_common/busybox/R.jar", + "out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar", + "out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar", + }, + directCombined: []string{ + "out/soong/.intermediates/direct/android_common/javac/direct.jar", + "out/soong/.intermediates/transitive/android_common/javac/transitive.jar", + "out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar", + }, + + transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"}, + transitiveOverlays: nil, + transitiveImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"}, + transitiveSrcJars: nil, + transitiveClasspath: []string{ + "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", + "out/soong/.intermediates/transitive/android_common/busybox/R.jar", + }, + transitiveCombined: nil, + + directImportResources: nil, + directImportOverlays: []string{"out/soong/.intermediates/direct_import/android_common/flat-res/gen_res.flata"}, + directImportImports: []string{ + "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", + "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk", + }, + + transitiveImportResources: nil, + transitiveImportOverlays: []string{"out/soong/.intermediates/transitive_import/android_common/flat-res/gen_res.flata"}, + transitiveImportImports: []string{ + "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", + "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", + }, + }, { + // Test an app building with resource processor enabled but with dependencies built without + // resource processor. + name: "app_resource_processor", + appUsesRP: true, + directLibUsesRP: false, + transitiveLibUsesRP: false, + + appResources: nil, + appOverlays: []string{ + "out/soong/.intermediates/transitive/android_common/package-res.apk", + "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", + "out/soong/.intermediates/transitive_import/android_common/package-res.apk", + "out/soong/.intermediates/direct/android_common/package-res.apk", + "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk", + "out/soong/.intermediates/direct_import/android_common/package-res.apk", + "out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat", + }, + appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"}, + appSrcJars: nil, + appClasspath: []string{ + "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", + // R.jar has to come before direct.jar + "out/soong/.intermediates/app/android_common/busybox/R.jar", + "out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar", + "out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar", + }, + appCombined: []string{ + "out/soong/.intermediates/app/android_common/busybox/R.jar", + "out/soong/.intermediates/app/android_common/javac/app.jar", + "out/soong/.intermediates/direct/android_common/combined/direct.jar", + "out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar", + }, + + dontVerifyDirect: true, + dontVerifyTransitive: true, + dontVerifyDirectImport: true, + dontVerifyTransitiveImport: true, + }, + { + // Test an app building without resource processor enabled but with a dependency built with + // resource processor. + name: "app_dependency_lib_resource_processor", + appUsesRP: false, + directLibUsesRP: true, + transitiveLibUsesRP: false, + + appOverlays: []string{ + "out/soong/.intermediates/transitive/android_common/package-res.apk", + "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", + "out/soong/.intermediates/transitive_import/android_common/package-res.apk", + "out/soong/.intermediates/direct/android_common/package-res.apk", + "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk", + "out/soong/.intermediates/direct_import/android_common/package-res.apk", + "out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat", + }, + appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"}, + appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"}, + appClasspath: []string{ + "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", + "out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar", + "out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar", + }, + appCombined: []string{ + "out/soong/.intermediates/app/android_common/javac/app.jar", + "out/soong/.intermediates/direct/android_common/combined/direct.jar", + "out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar", + }, + + directResources: nil, + directOverlays: []string{"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat"}, + directImports: []string{ + "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", + "out/soong/.intermediates/transitive_import/android_common/package-res.apk", + "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", + "out/soong/.intermediates/transitive/android_common/package-res.apk", + }, + directSrcJars: nil, + directClasspath: []string{ + "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", + "out/soong/.intermediates/transitive_import/android_common/busybox/R.jar", + "out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar", + "out/soong/.intermediates/direct/android_common/busybox/R.jar", + "out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar", + "out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar", + }, + directCombined: []string{ + "out/soong/.intermediates/direct/android_common/javac/direct.jar", + "out/soong/.intermediates/transitive/android_common/javac/transitive.jar", + "out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar", + }, + + dontVerifyTransitive: true, + dontVerifyDirectImport: true, + dontVerifyTransitiveImport: true, + }, + { + // Test a library building without resource processor enabled but with a dependency built with + // resource processor. + name: "lib_dependency_lib_resource_processor", + appUsesRP: false, + directLibUsesRP: false, + transitiveLibUsesRP: true, + + appOverlays: []string{ + "out/soong/.intermediates/transitive/android_common/package-res.apk", + "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", + "out/soong/.intermediates/transitive_import/android_common/package-res.apk", + "out/soong/.intermediates/direct/android_common/package-res.apk", + "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk", + "out/soong/.intermediates/direct_import/android_common/package-res.apk", + "out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat", + }, + appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"}, + appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"}, + appClasspath: []string{ + "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", + "out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar", + "out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar", + }, + appCombined: []string{ + "out/soong/.intermediates/app/android_common/javac/app.jar", + "out/soong/.intermediates/direct/android_common/combined/direct.jar", + "out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar", + }, + + directResources: nil, + directOverlays: []string{ + "out/soong/.intermediates/transitive/android_common/package-res.apk", + "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", + "out/soong/.intermediates/transitive_import/android_common/package-res.apk", + "out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat", + }, + directImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"}, + directSrcJars: []string{"out/soong/.intermediates/direct/android_common/gen/android/R.srcjar"}, + directClasspath: []string{ + "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", + "out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar", + "out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar", + }, + directCombined: []string{ + "out/soong/.intermediates/direct/android_common/javac/direct.jar", + "out/soong/.intermediates/transitive/android_common/javac/transitive.jar", + "out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar", + }, + + transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"}, + transitiveOverlays: nil, + transitiveImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"}, + transitiveSrcJars: nil, + transitiveClasspath: []string{ + "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", + "out/soong/.intermediates/transitive/android_common/busybox/R.jar", + }, + transitiveCombined: nil, + + dontVerifyDirectImport: true, + dontVerifyTransitiveImport: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + bp := fmt.Sprintf(` + android_app { + name: "app", + sdk_version: "current", + srcs: ["app/app.java"], + resource_dirs: ["app/res"], + manifest: "app/AndroidManifest.xml", + static_libs: ["direct", "direct_import"], + use_resource_processor: %v, + } + + android_library { + name: "direct", + sdk_version: "current", + srcs: ["direct/direct.java"], + resource_dirs: ["direct/res"], + manifest: "direct/AndroidManifest.xml", + static_libs: ["transitive", "transitive_import"], + use_resource_processor: %v, + } + + android_library { + name: "transitive", + sdk_version: "current", + srcs: ["transitive/transitive.java"], + resource_dirs: ["transitive/res"], + manifest: "transitive/AndroidManifest.xml", + use_resource_processor: %v, + } + + android_library_import { + name: "direct_import", + sdk_version: "current", + aars: ["direct_import.aar"], + static_libs: ["direct_import_dep"], + } + + android_library_import { + name: "direct_import_dep", + sdk_version: "current", + aars: ["direct_import_dep.aar"], + } + + android_library_import { + name: "transitive_import", + sdk_version: "current", + aars: ["transitive_import.aar"], + static_libs: ["transitive_import_dep"], + } + + android_library_import { + name: "transitive_import_dep", + sdk_version: "current", + aars: ["transitive_import_dep.aar"], + } + `, testCase.appUsesRP, testCase.directLibUsesRP, testCase.transitiveLibUsesRP) + + fs := android.MockFS{ + "app/res/values/strings.xml": nil, + "direct/res/values/strings.xml": nil, + "transitive/res/values/strings.xml": nil, + } + + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + PrepareForTestWithOverlayBuildComponents, + fs.AddToFixture(), + ).RunTestWithBp(t, bp) + + type aaptInfo struct { + resources, overlays, imports, srcJars, classpath, combined android.Paths + } + + getAaptInfo := func(moduleName string) (aaptInfo aaptInfo) { + mod := result.ModuleForTests(moduleName, "android_common") + resourceListRule := mod.MaybeOutput("aapt2/res.list") + overlayListRule := mod.MaybeOutput("aapt2/overlay.list") + aaptRule := mod.Rule("aapt2Link") + javacRule := mod.MaybeRule("javac") + combinedRule := mod.MaybeOutput("combined/" + moduleName + ".jar") + + aaptInfo.resources = resourceListRule.Inputs + aaptInfo.overlays = overlayListRule.Inputs + + aaptFlags := strings.Split(aaptRule.Args["flags"], " ") + for i, flag := range aaptFlags { + if flag == "-I" && i+1 < len(aaptFlags) { + aaptInfo.imports = append(aaptInfo.imports, android.PathForTesting(aaptFlags[i+1])) + } + } + + if len(javacRule.Args["srcJars"]) > 0 { + aaptInfo.srcJars = android.PathsForTesting(strings.Split(javacRule.Args["srcJars"], " ")...) + } + + if len(javacRule.Args["classpath"]) > 0 { + classpathArg := strings.TrimPrefix(javacRule.Args["classpath"], "-classpath ") + aaptInfo.classpath = android.PathsForTesting(strings.Split(classpathArg, ":")...) + } + + aaptInfo.combined = combinedRule.Inputs + return + } + + app := getAaptInfo("app") + direct := getAaptInfo("direct") + transitive := getAaptInfo("transitive") + directImport := getAaptInfo("direct_import") + transitiveImport := getAaptInfo("transitive_import") + + if !testCase.dontVerifyApp { + android.AssertPathsRelativeToTopEquals(t, "app resources", testCase.appResources, app.resources) + android.AssertPathsRelativeToTopEquals(t, "app overlays", testCase.appOverlays, app.overlays) + android.AssertPathsRelativeToTopEquals(t, "app imports", testCase.appImports, app.imports) + android.AssertPathsRelativeToTopEquals(t, "app srcjars", testCase.appSrcJars, app.srcJars) + android.AssertPathsRelativeToTopEquals(t, "app classpath", testCase.appClasspath, app.classpath) + android.AssertPathsRelativeToTopEquals(t, "app combined", testCase.appCombined, app.combined) + } + + if !testCase.dontVerifyDirect { + android.AssertPathsRelativeToTopEquals(t, "direct resources", testCase.directResources, direct.resources) + android.AssertPathsRelativeToTopEquals(t, "direct overlays", testCase.directOverlays, direct.overlays) + android.AssertPathsRelativeToTopEquals(t, "direct imports", testCase.directImports, direct.imports) + android.AssertPathsRelativeToTopEquals(t, "direct srcjars", testCase.directSrcJars, direct.srcJars) + android.AssertPathsRelativeToTopEquals(t, "direct classpath", testCase.directClasspath, direct.classpath) + android.AssertPathsRelativeToTopEquals(t, "direct combined", testCase.directCombined, direct.combined) + } + + if !testCase.dontVerifyTransitive { + android.AssertPathsRelativeToTopEquals(t, "transitive resources", testCase.transitiveResources, transitive.resources) + android.AssertPathsRelativeToTopEquals(t, "transitive overlays", testCase.transitiveOverlays, transitive.overlays) + android.AssertPathsRelativeToTopEquals(t, "transitive imports", testCase.transitiveImports, transitive.imports) + android.AssertPathsRelativeToTopEquals(t, "transitive srcjars", testCase.transitiveSrcJars, transitive.srcJars) + android.AssertPathsRelativeToTopEquals(t, "transitive classpath", testCase.transitiveClasspath, transitive.classpath) + android.AssertPathsRelativeToTopEquals(t, "transitive combined", testCase.transitiveCombined, transitive.combined) + } + + if !testCase.dontVerifyDirectImport { + android.AssertPathsRelativeToTopEquals(t, "direct_import resources", testCase.directImportResources, directImport.resources) + android.AssertPathsRelativeToTopEquals(t, "direct_import overlays", testCase.directImportOverlays, directImport.overlays) + android.AssertPathsRelativeToTopEquals(t, "direct_import imports", testCase.directImportImports, directImport.imports) + } + + if !testCase.dontVerifyTransitiveImport { + android.AssertPathsRelativeToTopEquals(t, "transitive_import resources", testCase.transitiveImportResources, transitiveImport.resources) + android.AssertPathsRelativeToTopEquals(t, "transitive_import overlays", testCase.transitiveImportOverlays, transitiveImport.overlays) + android.AssertPathsRelativeToTopEquals(t, "transitive_import imports", testCase.transitiveImportImports, transitiveImport.imports) + } + }) + } +} + +func TestAndroidResourceOverlays(t *testing.T) { testCases := []struct { name string enforceRROTargets []string @@ -943,7 +1453,7 @@ func TestAndroidResources(t *testing.T) { overlayFiles = resourceListToFiles(module, android.PathsRelativeToTop(overlayList.Inputs)) } - for _, d := range module.Module().(AndroidLibraryDependency).ExportedRRODirs() { + for _, d := range module.Module().(AndroidLibraryDependency).RRODirsDepSet().ToList() { var prefix string if d.overlayType == device { prefix = "device:" diff --git a/java/base.go b/java/base.go index f2ad5c2cf..f5eb01c4b 100644 --- a/java/base.go +++ b/java/base.go @@ -21,6 +21,7 @@ import ( "strings" "android/soong/ui/metrics/bp2build_metrics_proto" + "github.com/google/blueprint/pathtools" "github.com/google/blueprint/proptools" @@ -500,6 +501,21 @@ type Module struct { maxSdkVersion android.ApiLevel sourceExtensions []string + + annoSrcJars android.Paths + + // output file name based on Stem property. + // This should be set in every ModuleWithStem's GenerateAndroidBuildActions + // or the module should override Stem(). + stem string + + // Aconfig "cache files" that went directly into this module. Transitive ones are + // tracked via JavaInfo.TransitiveAconfigFiles + // TODO: Extract to something standalone to propagate tags via GeneratedJavaLibraryModule + aconfigIntermediates android.Paths + + // Aconfig files for all transitive deps. Also exposed via JavaInfo + transitiveAconfigFiles *android.DepSet[android.Path] } func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error { @@ -1049,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) @@ -1087,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") @@ -1097,7 +1111,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { j.expandJarjarRules = android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules) } - jarName := ctx.ModuleName() + ".jar" + jarName := j.Stem() + ".jar" var uniqueJavaFiles android.Paths set := make(map[string]bool) @@ -1132,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 @@ -1225,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 } @@ -1255,8 +1275,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // this module, or else we could have duplicated errorprone messages. errorproneFlags := enableErrorproneFlags(flags) errorprone := android.PathForModuleOut(ctx, "errorprone", jarName) + errorproneAnnoSrcJar := android.PathForModuleOut(ctx, "errorprone", "anno.srcjar") - transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneFlags, nil, + transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneAnnoSrcJar, errorproneFlags, nil, "errorprone", "errorprone") extraJarDeps = append(extraJarDeps, errorprone) @@ -1376,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 @@ -1468,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) @@ -1614,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, @@ -1628,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 @@ -1657,13 +1689,15 @@ func (j *Module) compileJavaClasses(ctx android.ModuleContext, jarName string, i srcFiles, srcJars android.Paths, flags javaBuilderFlags, extraJarDeps android.Paths) android.WritablePath { kzipName := pathtools.ReplaceExtension(jarName, "kzip") + annoSrcJar := android.PathForModuleOut(ctx, "javac", "anno.srcjar") if idx >= 0 { kzipName = strings.TrimSuffix(jarName, filepath.Ext(jarName)) + strconv.Itoa(idx) + ".kzip" + annoSrcJar = android.PathForModuleOut(ctx, "javac", "anno-"+strconv.Itoa(idx)+".srcjar") jarName += strconv.Itoa(idx) } classes := android.PathForModuleOut(ctx, "javac", jarName).OutputPath - TransformJavaToClasses(ctx, classes, idx, srcFiles, srcJars, flags, extraJarDeps) + TransformJavaToClasses(ctx, classes, idx, srcFiles, srcJars, annoSrcJar, flags, extraJarDeps) if ctx.Config().EmitXrefRules() { extractionFile := android.PathForModuleOut(ctx, kzipName) @@ -1671,6 +1705,10 @@ func (j *Module) compileJavaClasses(ctx android.ModuleContext, jarName string, i j.kytheFiles = append(j.kytheFiles, extractionFile) } + if len(flags.processorPath) > 0 { + j.annoSrcJars = append(j.annoSrcJars, annoSrcJar) + } + return classes } @@ -1850,6 +1888,7 @@ func (j *Module) IDEInfo(dpInfo *android.IdeInfo) { dpInfo.Paths = append(dpInfo.Paths, j.modulePaths...) dpInfo.Static_libs = append(dpInfo.Static_libs, j.properties.Static_libs...) dpInfo.Libs = append(dpInfo.Libs, j.properties.Libs...) + dpInfo.SrcJars = append(dpInfo.SrcJars, j.annoSrcJars.Strings()...) } func (j *Module) CompilerDeps() []string { @@ -1887,7 +1926,10 @@ func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersi } func (j *Module) Stem() string { - return proptools.StringDefault(j.overridableDeviceProperties.Stem, j.Name()) + if j.stem == "" { + panic("Stem() called before stem property was set") + } + return j.stem } func (j *Module) JacocoReportClassesFile() android.Path { @@ -1898,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/bootclasspath.go b/java/bootclasspath.go index f4cef7fa6..c7dc3afae 100644 --- a/java/bootclasspath.go +++ b/java/bootclasspath.go @@ -77,7 +77,7 @@ func addDependencyOntoApexVariants(ctx android.BottomUpMutatorContext, propertyN // Use gatherApexModulePairDepsWithTag to retrieve the dependencies. func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex string, name string, tag blueprint.DependencyTag) { var variations []blueprint.Variation - if apex != "platform" && apex != "system_ext" { + if !android.IsConfiguredJarForPlatform(apex) { // Pick the correct apex variant. variations = []blueprint.Variation{ {Mutator: "apex", Variation: apex}, @@ -185,6 +185,9 @@ var _ android.ExcludeFromVisibilityEnforcementTag = bootclasspathDependencyTag{} // The tag used for dependencies onto bootclasspath_fragments. var bootclasspathFragmentDepTag = bootclasspathDependencyTag{name: "fragment"} +// The tag used for dependencies onto platform_bootclasspath. +var platformBootclasspathDepTag = bootclasspathDependencyTag{name: "platform"} + // BootclasspathNestedAPIProperties defines properties related to the API provided by parts of the // bootclasspath that are nested within the main BootclasspathAPIProperties. type BootclasspathNestedAPIProperties struct { diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index 50429b07a..dcc2dece7 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -242,7 +242,7 @@ type BootclasspathFragmentModule struct { modulePaths []string // Path to the boot image profile. - profilePath android.Path + profilePath android.WritablePath } // commonBootclasspathFragment defines the methods that are implemented by both source and prebuilt @@ -256,16 +256,6 @@ type commonBootclasspathFragment interface { // versioned sdk. produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput - // produceBootImageFiles will attempt to produce rules to create the boot image files at the paths - // predefined in the bootImageConfig. - // - // If it could not create the files then it will return nil. Otherwise, it will return a map from - // android.ArchType to the predefined paths of the boot image files. - produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageOutputs - - // getImageName returns the `image_name` property of this fragment. - getImageName() *string - // getProfilePath returns the path to the boot image profile. getProfilePath() android.Path } @@ -295,9 +285,6 @@ func bootclasspathFragmentFactory() android.Module { return } } - - // Initialize the contents property from the image_name. - bootclasspathFragmentInitContentsFromImage(ctx, m) }) return m } @@ -308,9 +295,7 @@ func testBootclasspathFragmentFactory() android.Module { return m } -// bootclasspathFragmentInitContentsFromImage will initialize the contents property from the image_name if -// necessary. -func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext, m *BootclasspathFragmentModule) { +func (m *BootclasspathFragmentModule) bootclasspathFragmentPropertyCheck(ctx android.EarlyModuleContext) { contents := m.properties.Contents if len(contents) == 0 { ctx.PropertyErrorf("contents", "required property is missing") @@ -332,6 +317,18 @@ func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext, // too early in the Soong processing for that to work. global := dexpreopt.GetGlobalConfig(ctx) modules := global.ArtApexJars + configuredJars := modules.CopyOfJars() + + // Skip the check if the configured jars list is empty as that is a common configuration when + // building targets that do not result in a system image. + if len(configuredJars) == 0 { + return + } + + if !reflect.DeepEqual(configuredJars, contents) { + ctx.ModuleErrorf("inconsistency in specification of contents. ArtApexJars configuration specifies %#v, contents property specifies %#v", + configuredJars, contents) + } // Make sure that the apex specified in the configuration is consistent and is one for which // this boot image is available. @@ -357,42 +354,11 @@ func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext, } } -// bootclasspathImageNameContentsConsistencyCheck checks that the configuration that applies to this -// module (if any) matches the contents. -// -// This should be a noop as if image_name="art" then the contents will be set from the ArtApexJars -// config by bootclasspathFragmentInitContentsFromImage so it will be guaranteed to match. However, -// in future this will not be the case. -func (b *BootclasspathFragmentModule) bootclasspathImageNameContentsConsistencyCheck(ctx android.BaseModuleContext) { - imageName := proptools.String(b.properties.Image_name) - if imageName == "art" { - // Get the configuration for the art apex jars. - modules := b.getImageConfig(ctx).modules - configuredJars := modules.CopyOfJars() - - // Skip the check if the configured jars list is empty as that is a common configuration when - // building targets that do not result in a system image. - if len(configuredJars) == 0 { - return - } - - contents := b.properties.Contents - if !reflect.DeepEqual(configuredJars, contents) { - ctx.ModuleErrorf("inconsistency in specification of contents. ArtApexJars configuration specifies %#v, contents property specifies %#v", - configuredJars, contents) - } - } -} - var BootclasspathFragmentApexContentInfoProvider = blueprint.NewProvider(BootclasspathFragmentApexContentInfo{}) // BootclasspathFragmentApexContentInfo contains the bootclasspath_fragments contributions to the // apex contents. type BootclasspathFragmentApexContentInfo struct { - // The configured modules, will be empty if this is from a bootclasspath_fragment that does not - // set image_name: "art". - modules android.ConfiguredJarList - // Map from the base module name (without prebuilt_ prefix) of a fragment's contents module to the // hidden API encoded dex jar path. contentModuleDexJarPaths bootDexJarByModule @@ -405,10 +371,6 @@ type BootclasspathFragmentApexContentInfo struct { profileInstallPathInApex string } -func (i BootclasspathFragmentApexContentInfo) Modules() android.ConfiguredJarList { - return i.modules -} - // DexBootJarPathForContentModule returns the path to the dex boot jar for specified module. // // The dex boot jar is one which has had hidden API encoding performed on it. @@ -503,7 +465,7 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo // unused prebuilt that was created without instrumentation from breaking an instrumentation // build. if isActiveModule(ctx.Module()) { - b.bootclasspathImageNameContentsConsistencyCheck(ctx) + b.bootclasspathFragmentPropertyCheck(ctx) } // Generate classpaths.proto config @@ -523,34 +485,15 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo fragments := gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag) - // Verify that the image_name specified on a bootclasspath_fragment is valid even if this is a - // prebuilt which will not use the image config. - imageConfig := b.getImageConfig(ctx) - // Perform hidden API processing. hiddenAPIOutput := b.generateHiddenAPIBuildActions(ctx, contents, fragments) - var bootImageFiles bootImageOutputs - if imageConfig != nil { - // Delegate the production of the boot image files to a module type specific method. - common := ctx.Module().(commonBootclasspathFragment) - bootImageFiles = common.produceBootImageFiles(ctx, imageConfig) - b.profilePath = bootImageFiles.profile - - if shouldCopyBootFilesToPredefinedLocations(ctx, imageConfig) { - // Zip the boot image files up, if available. This will generate the zip file in a - // predefined location. - buildBootImageZipInPredefinedLocation(ctx, imageConfig, bootImageFiles.byArch) - - // Copy the dex jars of this fragment's content modules to their predefined locations. - copyBootJarsToPredefinedLocations(ctx, hiddenAPIOutput.EncodedBootDexFilesByModule, imageConfig.dexPathsByModule) - } - } - - // A prebuilt fragment cannot contribute to an apex. - if !android.IsModulePrebuilt(ctx.Module()) { - // Provide the apex content info. - b.provideApexContentInfo(ctx, imageConfig, hiddenAPIOutput, bootImageFiles) + if android.IsModulePrebuilt(ctx.Module()) { + b.profilePath = ctx.Module().(*PrebuiltBootclasspathFragmentModule).produceBootImageProfile(ctx) + } else { + b.profilePath = b.produceBootImageProfileFromSource(ctx, contents, hiddenAPIOutput.EncodedBootDexFilesByModule) + // Provide the apex content info. A prebuilt fragment cannot contribute to an apex. + b.provideApexContentInfo(ctx, hiddenAPIOutput, b.profilePath) } // In order for information about bootclasspath_fragment modules to be added to module-info.json @@ -564,45 +507,37 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo } } -// shouldCopyBootFilesToPredefinedLocations determines whether the current module should copy boot -// files, e.g. boot dex jars or boot image files, to the predefined location expected by the rest -// of the build. -// -// This ensures that only a single module will copy its files to the image configuration. -func shouldCopyBootFilesToPredefinedLocations(ctx android.ModuleContext, imageConfig *bootImageConfig) bool { - // Bootclasspath fragment modules that are for the platform do not produce boot related files. - apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) - if apexInfo.IsForPlatform() { - return false +// getProfileProviderApex returns the name of the apex that provides a boot image profile, or an +// empty string if this module should not provide a boot image profile. +func (b *BootclasspathFragmentModule) getProfileProviderApex(ctx android.BaseModuleContext) string { + // Only use the profile from the module that is preferred. + if !isActiveModule(ctx.Module()) { + return "" } - // If the image configuration has no modules specified then it means that the build has been - // configured to build something other than a boot image, e.g. an sdk, so do not try and copy the - // files. - if imageConfig.modules.Len() == 0 { - return false + // Bootclasspath fragment modules that are for the platform do not produce boot related files. + apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) + for _, apex := range apexInfo.InApexVariants { + if isProfileProviderApex(ctx, apex) { + return apex + } } - // Only copy files from the module that is preferred. - return isActiveModule(ctx.Module()) + return "" } // provideApexContentInfo creates, initializes and stores the apex content info for use by other // modules. -func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, hiddenAPIOutput *HiddenAPIOutput, bootImageFiles bootImageOutputs) { +func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, hiddenAPIOutput *HiddenAPIOutput, profile android.WritablePath) { // Construct the apex content info from the config. info := BootclasspathFragmentApexContentInfo{ // Populate the apex content info with paths to the dex jars. contentModuleDexJarPaths: hiddenAPIOutput.EncodedBootDexFilesByModule, } - if imageConfig != nil { - info.modules = imageConfig.modules - global := dexpreopt.GetGlobalConfig(ctx) - if !global.DisableGenerateProfile { - info.profilePathOnHost = bootImageFiles.profile - info.profileInstallPathInApex = imageConfig.profileInstallPathInApex - } + if profile != nil { + info.profilePathOnHost = profile + info.profileInstallPathInApex = profileInstallPathInApex } // Make the apex content info available for other modules. @@ -623,12 +558,12 @@ func (b *BootclasspathFragmentModule) generateClasspathProtoBuildActions(ctx and } func (b *BootclasspathFragmentModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList { + global := dexpreopt.GetGlobalConfig(ctx) + if "art" == proptools.String(b.properties.Image_name) { - return b.getImageConfig(ctx).modules + return global.ArtApexJars } - global := dexpreopt.GetGlobalConfig(ctx) - possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, b.properties.Contents, bootclasspathFragmentContentDepTag) jars, unknown := global.ApexBootJars.Filter(possibleUpdatableModules) @@ -654,25 +589,6 @@ func (b *BootclasspathFragmentModule) configuredJars(ctx android.ModuleContext) return jars } -func (b *BootclasspathFragmentModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig { - // Get a map of the image configs that are supported. - imageConfigs := genBootImageConfigs(ctx) - - // Retrieve the config for this image. - imageNamePtr := b.properties.Image_name - if imageNamePtr == nil { - return nil - } - - imageName := *imageNamePtr - imageConfig := imageConfigs[imageName] - if imageConfig == nil { - ctx.PropertyErrorf("image_name", "Unknown image name %q, expected one of %s", imageName, strings.Join(android.SortedKeys(imageConfigs), ", ")) - return nil - } - return imageConfig -} - // generateHiddenAPIBuildActions generates all the hidden API related build rules. func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) *HiddenAPIOutput { @@ -855,48 +771,22 @@ func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleC return output } -// produceBootImageFiles builds the boot image files from the source if it is required. -func (b *BootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageOutputs { - // Only generate the boot image if the configuration does not skip it. - return b.generateBootImageBuildActions(ctx, imageConfig) -} - -// generateBootImageBuildActions generates ninja rules to create the boot image if required for this -// module. -// -// If it could not create the files then it will return nil. Otherwise, it will return a map from -// android.ArchType to the predefined paths of the boot image files. -func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageOutputs { - global := dexpreopt.GetGlobalConfig(ctx) - if !shouldBuildBootImages(ctx.Config(), global) { - return bootImageOutputs{} - } - - // Bootclasspath fragment modules that are for the platform do not produce a boot image. - apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) - if apexInfo.IsForPlatform() { - return bootImageOutputs{} +// produceBootImageProfileFromSource builds the boot image profile from the source if it is required. +func (b *BootclasspathFragmentModule) produceBootImageProfileFromSource(ctx android.ModuleContext, contents []android.Module, modules bootDexJarByModule) android.WritablePath { + apex := b.getProfileProviderApex(ctx) + if apex == "" { + return nil } - // Build a profile for the image config and then use that to build the boot image. - profile := bootImageProfileRule(ctx, imageConfig) - - // If dexpreopt of boot image jars should be skipped, generate only a profile. - if SkipDexpreoptBootJars(ctx) { - return bootImageOutputs{ - profile: profile, - } + dexPaths := make(android.Paths, 0, len(contents)) + dexLocations := make([]string, 0, len(contents)) + for _, module := range contents { + dexPaths = append(dexPaths, modules[module.Name()]) + dexLocations = append(dexLocations, filepath.Join("/", "apex", apex, "javalib", module.Name() + ".jar")) } - // Build boot image files for the host variants. - buildBootImageVariantsForBuildOs(ctx, imageConfig, profile) - - // Build boot image files for the android variants. - bootImageFiles := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile) - - // Return the boot image files for the android variants for inclusion in an APEX and to be zipped - // up for the dist. - return bootImageFiles + // Build a profile for the modules in this fragment. + return bootImageProfileRuleCommon(ctx, b.Name(), dexPaths, dexLocations) } func (b *BootclasspathFragmentModule) AndroidMkEntries() []android.AndroidMkEntries { @@ -919,10 +809,6 @@ func (b *BootclasspathFragmentModule) AndroidMkEntries() []android.AndroidMkEntr return entriesList } -func (b *BootclasspathFragmentModule) getImageName() *string { - return b.properties.Image_name -} - func (b *BootclasspathFragmentModule) getProfilePath() android.Path { return b.profilePath } @@ -1192,39 +1078,19 @@ func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx an return &output } -// produceBootImageFiles extracts the boot image files from the APEX if available. -func (module *PrebuiltBootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageOutputs { - if !shouldCopyBootFilesToPredefinedLocations(ctx, imageConfig) { - return bootImageOutputs{} +// produceBootImageProfile extracts the boot image profile from the APEX if available. +func (module *PrebuiltBootclasspathFragmentModule) produceBootImageProfile(ctx android.ModuleContext) android.WritablePath { + // This module does not provide a boot image profile. + if module.getProfileProviderApex(ctx) == "" { + return nil } di := android.FindDeapexerProviderForModule(ctx) if di == nil { - return bootImageOutputs{} // An error has been reported by FindDeapexerProviderForModule. + return nil // An error has been reported by FindDeapexerProviderForModule. } - profile := (android.WritablePath)(nil) - if imageConfig.profileInstallPathInApex != "" { - profile = di.PrebuiltExportPath(imageConfig.profileInstallPathInApex) - } - - // Build the boot image files for the host variants. These are always built from the dex files - // provided by the contents of this module as prebuilt versions of the host boot image files are - // not available, i.e. there is no host specific prebuilt apex containing them. This has to be - // built without a profile as the prebuilt modules do not provide a profile. - buildBootImageVariantsForBuildOs(ctx, imageConfig, profile) - - if profile == nil && imageConfig.isProfileGuided() { - ctx.ModuleErrorf("Unable to produce boot image files: profiles not found in the prebuilt apex") - return bootImageOutputs{} - } - // Build boot image files for the android variants from the dex files provided by the contents - // of this module. - return buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile) -} - -func (b *PrebuiltBootclasspathFragmentModule) getImageName() *string { - return b.properties.Image_name + return di.PrebuiltExportPath(profileInstallPathInApex) } func (b *PrebuiltBootclasspathFragmentModule) getProfilePath() android.Path { @@ -1239,14 +1105,10 @@ var _ commonBootclasspathFragment = (*PrebuiltBootclasspathFragmentModule)(nil) // If there is no image config associated with this fragment then it returns nil. Otherwise, it // returns the files that are listed in the image config. func (module *PrebuiltBootclasspathFragmentModule) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) []string { - imageConfig := module.getImageConfig(ctx) - if imageConfig != nil { - files := []string{} - if imageConfig.profileInstallPathInApex != "" { - // Add the boot image profile. - files = append(files, imageConfig.profileInstallPathInApex) + for _, apex := range module.ApexProperties.Apex_available { + if isProfileProviderApex(ctx, apex) { + return []string{profileInstallPathInApex} } - return files } return nil } @@ -1262,9 +1124,5 @@ func prebuiltBootclasspathFragmentFactory() android.Module { android.InitApexModule(m) android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon) - // Initialize the contents property from the image_name. - android.AddLoadHook(m, func(ctx android.LoadHookContext) { - bootclasspathFragmentInitContentsFromImage(ctx, &m.BootclasspathFragmentModule) - }) return m } diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go index 2541f14ff..888caad16 100644 --- a/java/bootclasspath_fragment_test.go +++ b/java/bootclasspath_fragment_test.go @@ -40,6 +40,12 @@ func TestBootclasspathFragment_UnknownImageName(t *testing.T) { image_name: "unknown", contents: ["foo"], } + + java_library { + name: "foo", + srcs: ["foo.java"], + installable: true, + } `) } @@ -53,6 +59,11 @@ func TestPrebuiltBootclasspathFragment_UnknownImageName(t *testing.T) { image_name: "unknown", contents: ["foo"], } + + java_import { + name: "foo", + jars: ["foo.jar"], + } `) } @@ -72,6 +83,18 @@ func TestBootclasspathFragmentInconsistentArtConfiguration_Platform(t *testing.T "apex", ], } + + java_library { + name: "foo", + srcs: ["foo.java"], + installable: true, + } + + java_library { + name: "bar", + srcs: ["bar.java"], + installable: true, + } `) } @@ -92,6 +115,18 @@ func TestBootclasspathFragmentInconsistentArtConfiguration_ApexMixture(t *testin "apex2", ], } + + java_library { + name: "foo", + srcs: ["foo.java"], + installable: true, + } + + java_library { + name: "bar", + srcs: ["bar.java"], + installable: true, + } `) } diff --git a/java/builder.go b/java/builder.go index c4395e91d..afbd69ee4 100644 --- a/java/builder.go +++ b/java/builder.go @@ -42,7 +42,8 @@ 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" "$srcJarDir" "$out" && mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` + + 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 ` + `${config.SoongJavacWrapper} $javaTemplate${config.JavacCmd} ` + @@ -50,7 +51,10 @@ var ( `$processorpath $processor $javacFlags $bootClasspath $classpath ` + `-source $javaVersion -target $javaVersion ` + `-d $outDir -s $annoDir @$out.rsp @$srcJarDir/list ; fi ) && ` + - `$zipTemplate${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir && ` + + `$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"`, CommandDeps: []string{ "${config.JavacCmd}", @@ -58,6 +62,7 @@ var ( "${config.ZipSyncCmd}", }, CommandOrderOnly: []string{"${config.SoongJavacWrapper}"}, + Restat: true, Rspfile: "$out.rsp", RspfileContent: "$in", }, map[string]*remoteexec.REParams{ @@ -69,12 +74,19 @@ 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.tmp"}, ExecStrategy: "${config.REJavacExecStrategy}", Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, }, }, []string{"javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJars", "srcJarDir", - "outDir", "annoDir", "javaVersion"}, nil) + "outDir", "annoDir", "annoSrcJar", "javaVersion"}, nil) _ = pctx.VariableFunc("kytheCorpus", func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() }) @@ -259,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() { @@ -312,7 +330,7 @@ func DefaultJavaBuilderFlags() javaBuilderFlags { } func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath, shardIdx int, - srcFiles, srcJars android.Paths, flags javaBuilderFlags, deps android.Paths) { + srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath, flags javaBuilderFlags, deps android.Paths) { // Compile java sources into .class files desc := "javac" @@ -320,7 +338,7 @@ func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.Writab desc += strconv.Itoa(shardIdx) } - transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, flags, deps, "javac", desc) + transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, annoSrcJar, flags, deps, "javac", desc) } // Emits the rule to generate Xref input file (.kzip file) for the given set of source files and source jars @@ -494,7 +512,7 @@ func TurbineApt(ctx android.ModuleContext, outputSrcJar, outputResJar android.Wr // suffix will be appended to various intermediate files and directories to avoid collisions when // this function is called twice in the same module directory. func transformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath, - shardIdx int, srcFiles, srcJars android.Paths, + shardIdx int, srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath, flags javaBuilderFlags, deps android.Paths, intermediatesDir, desc string) { @@ -541,11 +559,12 @@ func transformJavaToClasses(ctx android.ModuleContext, outputFile android.Writab rule = javacRE } ctx.Build(pctx, android.BuildParams{ - Rule: rule, - Description: desc, - Output: outputFile, - Inputs: srcFiles, - Implicits: deps, + Rule: rule, + Description: desc, + Output: outputFile, + ImplicitOutput: annoSrcJar, + Inputs: srcFiles, + Implicits: deps, Args: map[string]string{ "javacFlags": flags.javacFlags, "bootClasspath": bootClasspath, @@ -556,6 +575,7 @@ func transformJavaToClasses(ctx android.ModuleContext, outputFile android.Writab "srcJarDir": android.PathForModuleOut(ctx, intermediatesDir, srcJarDir).String(), "outDir": android.PathForModuleOut(ctx, intermediatesDir, outDir).String(), "annoDir": android.PathForModuleOut(ctx, intermediatesDir, annoDir).String(), + "annoSrcJar": annoSrcJar.String(), "javaVersion": flags.javaVersion.String(), }, }) @@ -619,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/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/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 2b0f57e82..003f2de22 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -16,7 +16,6 @@ package java import ( "path/filepath" - "sort" "strings" "android/soong/android" @@ -224,6 +223,11 @@ var artApexNames = []string{ "com.google.android.art.testing", } +var ( + dexpreoptBootJarDepTag = bootclasspathDependencyTag{name: "dexpreopt-boot-jar"} + dexBootJarsFragmentsKey = android.NewOnceKey("dexBootJarsFragments") +) + func init() { RegisterDexpreoptBootJarsComponents(android.InitRegistrationContext) } @@ -241,6 +245,9 @@ type bootImageConfig struct { // Image name (used in directory names and ninja rule names). name string + // If the module with the given name exists, this config is enabled. + enabledIfExists string + // Basename of the image: the resulting filenames are <stem>[-<jar>].{art,oat,vdex}. stem string @@ -257,10 +264,6 @@ type bootImageConfig struct { // the location is relative to "/". installDir string - // Install path of the boot image profile if it needs to be installed in the APEX, or empty if not - // needed. - profileInstallPathInApex string - // A list of (location, jar) pairs for the Java modules in this image. modules android.ConfiguredJarList @@ -296,10 +299,9 @@ type bootImageConfig struct { // The "--single-image" argument. singleImage bool - // Profiles imported from other boot image configs. Each element must represent a - // `bootclasspath_fragment` of an APEX (i.e., the `name` field of each element must refer to the - // `image_name` property of a `bootclasspath_fragment`). - profileImports []*bootImageConfig + // Profiles imported from APEXes, in addition to the profile at the default path. Each entry must + // be the name of an APEX module. + profileImports []string } // Target-dependent description of a boot image. @@ -384,7 +386,7 @@ func (image bootImageConfig) moduleName(ctx android.PathContext, idx int) string m := image.modules.Jar(idx) name := image.stem if idx != 0 || image.extends != nil { - name += "-" + android.ModuleStem(m) + name += "-" + android.ModuleStem(ctx.Config(), image.modules.Apex(idx), m) } return name } @@ -458,18 +460,26 @@ func (image *bootImageConfig) isProfileGuided() bool { return image.compilerFilter == "speed-profile" } +func (image *bootImageConfig) isEnabled(ctx android.BaseModuleContext) bool { + return ctx.OtherModuleExists(image.enabledIfExists) +} + func dexpreoptBootJarsFactory() android.SingletonModule { m := &dexpreoptBootJars{} - android.InitAndroidModule(m) + android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) return m } func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) { ctx.RegisterParallelSingletonModuleType("dex_bootjars", dexpreoptBootJarsFactory) + ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("dex_bootjars_deps", DexpreoptBootJarsMutator).Parallel() + }) } func SkipDexpreoptBootJars(ctx android.PathContext) bool { - return dexpreopt.GetGlobalConfig(ctx).DisablePreoptBootImages + global := dexpreopt.GetGlobalConfig(ctx) + return global.DisablePreoptBootImages || !shouldBuildBootImages(ctx.Config(), global) } // Singleton module for generating boot image build rules. @@ -492,39 +502,90 @@ type dexpreoptBootJars struct { dexpreoptConfigForMake android.WritablePath } -// Provide paths to boot images for use by modules that depend upon them. -// -// The build rules are created in GenerateSingletonBuildActions(). -func (d *dexpreoptBootJars) GenerateAndroidBuildActions(ctx android.ModuleContext) { - // Placeholder for now. -} - -// Generate build rules for boot images. -func (d *dexpreoptBootJars) GenerateSingletonBuildActions(ctx android.SingletonContext) { - if dexpreopt.GetCachedGlobalSoongConfig(ctx) == nil { - // No module has enabled dexpreopting, so we assume there will be no boot image to make. +func DexpreoptBootJarsMutator(ctx android.BottomUpMutatorContext) { + if _, ok := ctx.Module().(*dexpreoptBootJars); !ok { return } - archType := ctx.Config().Targets[android.Android][0].Arch.ArchType - d.dexpreoptConfigForMake = android.PathForOutput(ctx, toDexpreoptDirName(archType), "dexpreopt.config") - writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake) - global := dexpreopt.GetGlobalConfig(ctx) - if !shouldBuildBootImages(ctx.Config(), global) { - return + if dexpreopt.IsDex2oatNeeded(ctx) { + // Add a dependency onto the dex2oat tool which is needed for creating the boot image. The + // path is retrieved from the dependency by GetGlobalSoongConfig(ctx). + dexpreopt.RegisterToolDeps(ctx) } - defaultImageConfig := defaultBootImageConfig(ctx) - d.defaultBootImage = defaultImageConfig imageConfigs := genBootImageConfigs(ctx) - d.otherImages = make([]*bootImageConfig, 0, len(imageConfigs)-1) for _, config := range imageConfigs { - if config != defaultImageConfig { + if !config.isEnabled(ctx) { + continue + } + // For accessing the boot jars. + addDependenciesOntoBootImageModules(ctx, config.modules, dexpreoptBootJarDepTag) + } + + if ctx.OtherModuleExists("platform-bootclasspath") { + // For accessing all bootclasspath fragments. + addDependencyOntoApexModulePair(ctx, "platform", "platform-bootclasspath", platformBootclasspathDepTag) + } else if ctx.OtherModuleExists("art-bootclasspath-fragment") { + // For accessing the ART bootclasspath fragment on a thin manifest (e.g., master-art) where + // platform-bootclasspath doesn't exist. + addDependencyOntoApexModulePair(ctx, "com.android.art", "art-bootclasspath-fragment", bootclasspathFragmentDepTag) + } +} + +func gatherBootclasspathFragments(ctx android.ModuleContext) map[string]android.Module { + return ctx.Config().Once(dexBootJarsFragmentsKey, func() interface{} { + fragments := make(map[string]android.Module) + ctx.WalkDeps(func(child, parent android.Module) bool { + if !isActiveModule(child) { + return false + } + tag := ctx.OtherModuleDependencyTag(child) + if tag == platformBootclasspathDepTag { + return true + } + if tag == bootclasspathFragmentDepTag { + apexInfo := ctx.OtherModuleProvider(child, android.ApexInfoProvider).(android.ApexInfo) + for _, apex := range apexInfo.InApexVariants { + fragments[apex] = child + } + return false + } + return false + }) + return fragments + }).(map[string]android.Module) +} + +func getBootclasspathFragmentByApex(ctx android.ModuleContext, apexName string) android.Module { + return gatherBootclasspathFragments(ctx)[apexName] +} + +// GenerateAndroidBuildActions generates the build rules for boot images. +func (d *dexpreoptBootJars) GenerateAndroidBuildActions(ctx android.ModuleContext) { + imageConfigs := genBootImageConfigs(ctx) + d.defaultBootImage = defaultBootImageConfig(ctx) + d.otherImages = make([]*bootImageConfig, 0, len(imageConfigs)-1) + for _, name := range getImageNames() { + config := imageConfigs[name] + if config != d.defaultBootImage { d.otherImages = append(d.otherImages, config) } + if !config.isEnabled(ctx) { + continue + } + generateBootImage(ctx, config) + if config == d.defaultBootImage { + bootFrameworkProfileRule(ctx, config) + } } } +// GenerateSingletonBuildActions generates build rules for the dexpreopt config for Make. +func (d *dexpreoptBootJars) GenerateSingletonBuildActions(ctx android.SingletonContext) { + d.dexpreoptConfigForMake = android.PathForOutput(ctx, getDexpreoptDirName(ctx), "dexpreopt.config") + writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake) +} + // shouldBuildBootImages determines whether boot images should be built. func shouldBuildBootImages(config android.Config, global *dexpreopt.GlobalConfig) bool { // Skip recompiling the boot image for the second sanitization phase. We'll get separate paths @@ -537,6 +598,101 @@ func shouldBuildBootImages(config android.Config, global *dexpreopt.GlobalConfig return true } +func generateBootImage(ctx android.ModuleContext, imageConfig *bootImageConfig) { + apexJarModulePairs := getModulesForImage(ctx, imageConfig) + + // Copy module dex jars to their predefined locations. + bootDexJarsByModule := extractEncodedDexJarsFromModulesOrBootclasspathFragments(ctx, apexJarModulePairs) + copyBootJarsToPredefinedLocations(ctx, bootDexJarsByModule, imageConfig.dexPathsByModule) + + // Build a profile for the image config from the profile at the default path. The profile will + // then be used along with profiles imported from APEXes to build the boot image. + profile := bootImageProfileRule(ctx, imageConfig) + + // If dexpreopt of boot image jars should be skipped, stop after generating a profile. + if SkipDexpreoptBootJars(ctx) { + return + } + + // Build boot image files for the android variants. + androidBootImageFiles := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile) + + // Zip the android variant boot image files up. + buildBootImageZipInPredefinedLocation(ctx, imageConfig, androidBootImageFiles.byArch) + + // Build boot image files for the host variants. There are use directly by ART host side tests. + buildBootImageVariantsForBuildOs(ctx, imageConfig, profile) + + // Create a `dump-oat-<image-name>` rule that runs `oatdump` for debugging purposes. + dumpOatRules(ctx, imageConfig) +} + +type apexJarModulePair struct { + apex string + jarModule android.Module +} + +func getModulesForImage(ctx android.ModuleContext, imageConfig *bootImageConfig) []apexJarModulePair { + modules := make([]apexJarModulePair, 0, imageConfig.modules.Len()) + for i := 0; i < imageConfig.modules.Len(); i++ { + found := false + for _, module := range gatherApexModulePairDepsWithTag(ctx, dexpreoptBootJarDepTag) { + name := android.RemoveOptionalPrebuiltPrefix(module.Name()) + if name == imageConfig.modules.Jar(i) { + modules = append(modules, apexJarModulePair{ + apex: imageConfig.modules.Apex(i), + jarModule: module, + }) + found = true + break + } + } + if !found && !ctx.Config().AllowMissingDependencies() { + ctx.ModuleErrorf( + "Boot image '%s' module '%s' not added as a dependency of dex_bootjars", + imageConfig.name, + imageConfig.modules.Jar(i)) + return []apexJarModulePair{} + } + } + return modules +} + +// extractEncodedDexJarsFromModulesOrBootclasspathFragments gets the hidden API encoded dex jars for +// the given modules. +func extractEncodedDexJarsFromModulesOrBootclasspathFragments(ctx android.ModuleContext, apexJarModulePairs []apexJarModulePair) bootDexJarByModule { + encodedDexJarsByModuleName := bootDexJarByModule{} + for _, pair := range apexJarModulePairs { + var path android.Path + if android.IsConfiguredJarForPlatform(pair.apex) || android.IsModulePrebuilt(pair.jarModule) { + // This gives us the dex jar with the hidden API flags encoded from the monolithic hidden API + // files or the dex jar extracted from a prebuilt APEX. We can't use this for a boot jar for + // a source APEX because there is no guarantee that it is the same as the jar packed into the + // APEX. In practice, they are the same when we are building from a full source tree, but they + // are different when we are building from a thin manifest (e.g., master-art), where there is + // no monolithic hidden API files at all. + path = retrieveEncodedBootDexJarFromModule(ctx, pair.jarModule) + } else { + // Use exactly the same jar that is packed into the APEX. + fragment := getBootclasspathFragmentByApex(ctx, pair.apex) + if fragment == nil { + ctx.ModuleErrorf("Boot jar '%[1]s' is from APEX '%[2]s', but a bootclasspath_fragment for "+ + "APEX '%[2]s' doesn't exist or is not added as a dependency of dex_bootjars", + pair.jarModule.Name(), + pair.apex) + } + bootclasspathFragmentInfo := ctx.OtherModuleProvider(fragment, BootclasspathFragmentApexContentInfoProvider).(BootclasspathFragmentApexContentInfo) + jar, err := bootclasspathFragmentInfo.DexBootJarPathForContentModule(pair.jarModule) + if err != nil { + ctx.ModuleErrorf("%s", err) + } + path = jar + } + encodedDexJarsByModuleName.addPath(pair.jarModule, path) + } + return encodedDexJarsByModuleName +} + // copyBootJarsToPredefinedLocations generates commands that will copy boot jars to predefined // paths in the global config. func copyBootJarsToPredefinedLocations(ctx android.ModuleContext, srcBootDexJarsByModule bootDexJarByModule, dstBootJarsByModule map[string]android.WritablePath) { @@ -687,10 +843,12 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p rule.Command().Text("rm").Flag("-f"). Flag(symbolsDir.Join(ctx, "*.art").String()). Flag(symbolsDir.Join(ctx, "*.oat").String()). + Flag(symbolsDir.Join(ctx, "*.vdex").String()). Flag(symbolsDir.Join(ctx, "*.invocation").String()) rule.Command().Text("rm").Flag("-f"). Flag(outputDir.Join(ctx, "*.art").String()). Flag(outputDir.Join(ctx, "*.oat").String()). + Flag(outputDir.Join(ctx, "*.vdex").String()). Flag(outputDir.Join(ctx, "*.invocation").String()) cmd := rule.Command() @@ -712,36 +870,31 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p Flag("--runtime-arg").FlagWithArg("-Xms", global.Dex2oatImageXms). Flag("--runtime-arg").FlagWithArg("-Xmx", global.Dex2oatImageXmx) - if profile != nil { - cmd.FlagWithInput("--profile-file=", profile) - } - - fragments := make(map[string]commonBootclasspathFragment) - ctx.VisitDirectDepsWithTag(bootclasspathFragmentDepTag, func(child android.Module) { - fragment := child.(commonBootclasspathFragment) - if fragment.getImageName() != nil && android.IsModulePreferred(child) { - fragments[*fragment.getImageName()] = fragment + if image.isProfileGuided() && !global.DisableGenerateProfile { + if profile != nil { + cmd.FlagWithInput("--profile-file=", profile) } - }) - for _, profileImport := range image.profileImports { - fragment := fragments[profileImport.name] - if fragment == nil { - ctx.ModuleErrorf("Boot image config '%[1]s' imports profile from '%[2]s', but a "+ - "bootclasspath_fragment with image name '%[2]s' doesn't exist or is not added as a "+ - "dependency of '%[1]s'", - image.name, - profileImport.name) - return bootImageVariantOutputs{} - } - if fragment.getProfilePath() == nil { - ctx.ModuleErrorf("Boot image config '%[1]s' imports profile from '%[2]s', but '%[2]s' "+ - "doesn't provide a profile", - image.name, - profileImport.name) - return bootImageVariantOutputs{} + for _, apex := range image.profileImports { + fragment := getBootclasspathFragmentByApex(ctx, apex) + if fragment == nil { + ctx.ModuleErrorf("Boot image config '%[1]s' imports profile from '%[2]s', but a "+ + "bootclasspath_fragment for APEX '%[2]s' doesn't exist or is not added as a "+ + "dependency of dex_bootjars", + image.name, + apex) + return bootImageVariantOutputs{} + } + importedProfile := fragment.(commonBootclasspathFragment).getProfilePath() + if importedProfile == nil { + ctx.ModuleErrorf("Boot image config '%[1]s' imports profile from '%[2]s', but '%[2]s' "+ + "doesn't provide a profile", + image.name, + apex) + return bootImageVariantOutputs{} + } + cmd.FlagWithInput("--profile-file=", importedProfile) } - cmd.FlagWithInput("--profile-file=", fragment.getProfilePath()) } dirtyImageFile := "frameworks/base/config/dirty-image-objects" @@ -885,11 +1038,7 @@ const failureMessage = `ERROR: Dex2oat failed to compile a boot image. It is likely that the boot classpath is inconsistent. Rebuild with ART_BOOT_IMAGE_EXTRA_ARGS="--runtime-arg -verbose:verifier" to see verification errors.` -func bootImageProfileRule(ctx android.ModuleContext, image *bootImageConfig) android.WritablePath { - if !image.isProfileGuided() { - return nil - } - +func bootImageProfileRuleCommon(ctx android.ModuleContext, name string, dexFiles android.Paths, dexLocations []string) android.WritablePath { globalSoong := dexpreopt.GetGlobalSoongConfig(ctx) global := dexpreopt.GetGlobalConfig(ctx) @@ -916,28 +1065,39 @@ func bootImageProfileRule(ctx android.ModuleContext, image *bootImageConfig) and if path := android.ExistentPathForSource(ctx, extraProfile); path.Valid() { profiles = append(profiles, path.Path()) } - bootImageProfile := image.dir.Join(ctx, "boot-image-profile.txt") + bootImageProfile := android.PathForModuleOut(ctx, name, "boot-image-profile.txt") rule.Command().Text("cat").Inputs(profiles).Text(">").Output(bootImageProfile) - profile := image.dir.Join(ctx, "boot.prof") + profile := android.PathForModuleOut(ctx, name, "boot.prof") rule.Command(). Text(`ANDROID_LOG_TAGS="*:e"`). Tool(globalSoong.Profman). Flag("--output-profile-type=boot"). FlagWithInput("--create-profile-from=", bootImageProfile). - FlagForEachInput("--apk=", image.dexPathsDeps.Paths()). - FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps). + FlagForEachInput("--apk=", dexFiles). + FlagForEachArg("--dex-location=", dexLocations). FlagWithOutput("--reference-profile-file=", profile) + rule.Build("bootJarsProfile_"+name, "profile boot jars "+name) + + return profile +} + +func bootImageProfileRule(ctx android.ModuleContext, image *bootImageConfig) android.WritablePath { + if !image.isProfileGuided() { + return nil + } + + profile := bootImageProfileRuleCommon(ctx, image.name, image.dexPathsDeps.Paths(), image.getAnyAndroidVariant().dexLocationsDeps) + if image == defaultBootImageConfig(ctx) { + rule := android.NewRuleBuilder(pctx, ctx) rule.Install(profile, "/system/etc/boot-image.prof") image.profileInstalls = append(image.profileInstalls, rule.Installs()...) image.profileLicenseMetadataFile = android.OptionalPathForPath(ctx.LicenseMetadataFile()) } - rule.Build("bootJarsProfile", "profile boot jars") - return profile } @@ -976,6 +1136,8 @@ func bootFrameworkProfileRule(ctx android.ModuleContext, image *bootImageConfig) func dumpOatRules(ctx android.ModuleContext, image *bootImageConfig) { var allPhonies android.Paths + name := image.name + global := dexpreopt.GetGlobalConfig(ctx) for _, image := range image.variants { arch := image.target.Arch.ArchType suffix := arch.String() @@ -984,36 +1146,39 @@ func dumpOatRules(ctx android.ModuleContext, image *bootImageConfig) { suffix = "host-" + suffix } // Create a rule to call oatdump. - output := android.PathForOutput(ctx, "boot."+suffix+".oatdump.txt") + output := android.PathForOutput(ctx, name+"."+suffix+".oatdump.txt") rule := android.NewRuleBuilder(pctx, ctx) imageLocationsOnHost, _ := image.imageLocations() - rule.Command(). + cmd := rule.Command(). BuiltTool("oatdump"). FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":"). FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":"). FlagWithArg("--image=", strings.Join(imageLocationsOnHost, ":")).Implicits(image.imagesDeps.Paths()). FlagWithOutput("--output=", output). FlagWithArg("--instruction-set=", arch.String()) - rule.Build("dump-oat-boot-"+suffix, "dump oat boot "+arch.String()) + if global.EnableUffdGc && image.target.Os == android.Android { + cmd.Flag("--runtime-arg").Flag("-Xgc:CMC") + } + rule.Build("dump-oat-"+name+"-"+suffix, "dump oat "+name+" "+arch.String()) // Create a phony rule that depends on the output file and prints the path. - phony := android.PathForPhony(ctx, "dump-oat-boot-"+suffix) + phony := android.PathForPhony(ctx, "dump-oat-"+name+"-"+suffix) rule = android.NewRuleBuilder(pctx, ctx) rule.Command(). Implicit(output). ImplicitOutput(phony). Text("echo").FlagWithArg("Output in ", output.String()) - rule.Build("phony-dump-oat-boot-"+suffix, "dump oat boot "+arch.String()) + rule.Build("phony-dump-oat-"+name+"-"+suffix, "dump oat "+name+" "+arch.String()) allPhonies = append(allPhonies, phony) } - phony := android.PathForPhony(ctx, "dump-oat-boot") + phony := android.PathForPhony(ctx, "dump-oat-"+name) ctx.Build(pctx, android.BuildParams{ Rule: android.Phony, Output: phony, Inputs: allPhonies, - Description: "dump-oat-boot", + Description: "dump-oat-"+name, }) } @@ -1048,11 +1213,9 @@ func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) { ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(dexPaths.Strings(), " ")) ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(dexLocations, " ")) - var imageNames []string // The primary ART boot image is exposed to Make for testing (gtests) and benchmarking // (golem) purposes. for _, current := range append(d.otherImages, image) { - imageNames = append(imageNames, current.name) for _, variant := range current.variants { suffix := "" if variant.target.Os.Class == android.Host { @@ -1073,8 +1236,6 @@ func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) { ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICE"+current.name, strings.Join(imageLocationsOnDevice, ":")) ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+current.name, current.zip.String()) } - // Ensure determinism. - sort.Strings(imageNames) - ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(imageNames, " ")) + ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(getImageNames(), " ")) } } diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go index 28f50d7e3..0f4bd9b34 100644 --- a/java/dexpreopt_config.go +++ b/java/dexpreopt_config.go @@ -40,57 +40,67 @@ func dexpreoptTargets(ctx android.PathContext) []android.Target { } var ( - bootImageConfigKey = android.NewOnceKey("bootImageConfig") - bootImageConfigRawKey = android.NewOnceKey("bootImageConfigRaw") - artBootImageName = "art" - frameworkBootImageName = "boot" - mainlineBootImageName = "mainline" - bootImageStem = "boot" + bootImageConfigKey = android.NewOnceKey("bootImageConfig") + bootImageConfigRawKey = android.NewOnceKey("bootImageConfigRaw") + frameworkBootImageName = "boot" + mainlineBootImageName = "mainline" + bootImageStem = "boot" + profileInstallPathInApex = "etc/boot-image.prof" ) +// getImageNames returns an ordered list of image names. The order doesn't matter but needs to be +// deterministic. The names listed here must match the map keys returned by genBootImageConfigs. +func getImageNames() []string { + return []string{"art", "boot", "mainline"} +} + func genBootImageConfigRaw(ctx android.PathContext) map[string]*bootImageConfig { return ctx.Config().Once(bootImageConfigRawKey, func() interface{} { global := dexpreopt.GetGlobalConfig(ctx) - artModules := global.ArtApexJars - frameworkModules := global.BootJars // This includes `artModules`. + artBootImageName := "art" // Keep this local to avoid accidental references. + frameworkModules := global.BootJars // This includes `global.ArtApexJars`. mainlineBcpModules := global.ApexBootJars frameworkSubdir := "system/framework" - // ART config for the primary boot image in the ART apex. - // It includes the Core Libraries. + profileImports := []string{"com.android.art"} + + // ART boot image for testing only. Do not rely on it to make any build-time decision. artCfg := bootImageConfig{ - name: artBootImageName, - stem: bootImageStem, - installDir: "apex/art_boot_images/javalib", - profileInstallPathInApex: "etc/boot-image.prof", - modules: artModules, - preloadedClassesFile: "art/build/boot/preloaded-classes", - compilerFilter: "speed-profile", - singleImage: false, + name: artBootImageName, + enabledIfExists: "art-bootclasspath-fragment", + stem: bootImageStem, + installDir: "apex/art_boot_images/javalib", + modules: global.TestOnlyArtBootImageJars, + preloadedClassesFile: "art/build/boot/preloaded-classes", + compilerFilter: "speed-profile", + singleImage: false, + profileImports: profileImports, } // Framework config for the boot image extension. // It includes framework libraries and depends on the ART config. frameworkCfg := bootImageConfig{ name: frameworkBootImageName, + enabledIfExists: "platform-bootclasspath", stem: bootImageStem, installDir: frameworkSubdir, modules: frameworkModules, preloadedClassesFile: "frameworks/base/config/preloaded-classes", compilerFilter: "speed-profile", singleImage: false, - profileImports: []*bootImageConfig{&artCfg}, + profileImports: profileImports, } mainlineCfg := bootImageConfig{ - extends: &frameworkCfg, - name: mainlineBootImageName, - stem: bootImageStem, - installDir: frameworkSubdir, - modules: mainlineBcpModules, - compilerFilter: "verify", - singleImage: true, + extends: &frameworkCfg, + name: mainlineBootImageName, + enabledIfExists: "platform-bootclasspath", + stem: bootImageStem, + installDir: frameworkSubdir, + modules: mainlineBcpModules, + compilerFilter: "verify", + singleImage: true, } return map[string]*bootImageConfig{ @@ -105,8 +115,7 @@ func genBootImageConfigRaw(ctx android.PathContext) map[string]*bootImageConfig func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig { return ctx.Config().Once(bootImageConfigKey, func() interface{} { targets := dexpreoptTargets(ctx) - archType := ctx.Config().Targets[android.Android][0].Arch.ArchType - deviceDir := android.PathForOutput(ctx, toDexpreoptDirName(archType)) + deviceDir := android.PathForOutput(ctx, getDexpreoptDirName(ctx)) configs := genBootImageConfigRaw(ctx) @@ -181,10 +190,6 @@ func calculateDepsRecursive(c *bootImageConfig, targets []android.Target, visite } } -func artBootImageConfig(ctx android.PathContext) *bootImageConfig { - return genBootImageConfigs(ctx)[artBootImageName] -} - func defaultBootImageConfig(ctx android.PathContext) *bootImageConfig { return genBootImageConfigs(ctx)[frameworkBootImageName] } @@ -193,6 +198,18 @@ func mainlineBootImageConfig(ctx android.PathContext) *bootImageConfig { return genBootImageConfigs(ctx)[mainlineBootImageName] } +// isProfileProviderApex returns true if this apex provides a boot image profile. +func isProfileProviderApex(ctx android.PathContext, apexName string) bool { + for _, config := range genBootImageConfigs(ctx) { + for _, profileImport := range config.profileImports { + if profileImport == apexName { + return true + } + } + } + return false +} + // Apex boot config allows to access build/install paths of apex boot jars without going // through the usual trouble of registering dependencies on those modules and extracting build paths // from those dependencies. @@ -218,8 +235,7 @@ var updatableBootConfigKey = android.NewOnceKey("apexBootConfig") func GetApexBootConfig(ctx android.PathContext) apexBootConfig { return ctx.Config().Once(updatableBootConfigKey, func() interface{} { apexBootJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars - archType := ctx.Config().Targets[android.Android][0].Arch.ArchType - dir := android.PathForOutput(ctx, toDexpreoptDirName(archType), "apex_bootjars") + dir := android.PathForOutput(ctx, getDexpreoptDirName(ctx), "apex_bootjars") dexPaths := apexBootJars.BuildPaths(ctx, dir) dexPathsByModuleName := apexBootJars.BuildPathsByModule(ctx, dir) @@ -258,6 +274,11 @@ func dexpreoptConfigMakevars(ctx android.MakeVarsContext) { ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules.CopyOfApexJarPairs(), ":")) } -func toDexpreoptDirName(arch android.ArchType) string { - return "dexpreopt_" + arch.String() +func getDexpreoptDirName(ctx android.PathContext) string { + prefix := "dexpreopt_" + targets := ctx.Config().Targets[android.Android] + if len(targets) > 0 { + return prefix+targets[0].Arch.ArchType.String() + } + return prefix+"unknown_target" } diff --git a/java/dexpreopt_config_test.go b/java/dexpreopt_config_test.go index cd7f295c8..44d2127fd 100644 --- a/java/dexpreopt_config_test.go +++ b/java/dexpreopt_config_test.go @@ -16,6 +16,7 @@ package java import ( "runtime" + "sort" "testing" "android/soong/android" @@ -35,3 +36,22 @@ func TestBootImageConfig(t *testing.T) { CheckFrameworkBootImageConfig(t, result) CheckMainlineBootImageConfig(t, result) } + +func TestImageNames(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForBootImageConfigTest, + ).RunTest(t) + + names := getImageNames() + sort.Strings(names) + + ctx := &android.TestPathContext{TestResult: result} + configs := genBootImageConfigs(ctx) + namesFromConfigs := make([]string, 0, len(configs)) + for name, _ := range configs { + namesFromConfigs = append(namesFromConfigs, name) + } + sort.Strings(namesFromConfigs) + + android.AssertArrayString(t, "getImageNames vs genBootImageConfigs", names, namesFromConfigs) +} diff --git a/java/dexpreopt_config_testing.go b/java/dexpreopt_config_testing.go index 6f3aa2be8..176c251fd 100644 --- a/java/dexpreopt_config_testing.go +++ b/java/dexpreopt_config_testing.go @@ -29,6 +29,7 @@ import ( "testing" "android/soong/android" + "android/soong/dexpreopt" ) // PrepareForBootImageConfigTest is the minimal set of preparers that are needed to be able to use @@ -36,7 +37,17 @@ import ( var PrepareForBootImageConfigTest = android.GroupFixturePreparers( android.PrepareForTestWithArchMutator, android.PrepareForTestAccessingMakeVars, + PrepareForTestWithDexpreopt, FixtureConfigureBootJars("com.android.art:core1", "com.android.art:core2", "platform:framework"), + dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:core1", "com.android.art:core2", "platform:extra1"), + android.FixtureAddTextFile("extra1/Android.bp", ` + java_library { + name: "extra1", + srcs: ["extra1.java"], + installable: true, + } + `), + android.FixtureAddFile("extra1/extra1.java", nil), ) var PrepareApexBootJarConfigs = FixtureConfigureApexBootJars( @@ -44,18 +55,18 @@ var PrepareApexBootJarConfigs = FixtureConfigureApexBootJars( var PrepareApexBootJarConfigsAndModules = android.GroupFixturePreparers( PrepareApexBootJarConfigs, - prepareApexBootJarModule("com.android.foo", "framework-foo"), - prepareApexBootJarModule("com.android.bar", "framework-bar"), + PrepareApexBootJarModule("com.android.foo", "framework-foo"), + PrepareApexBootJarModule("com.android.bar", "framework-bar"), ) var ApexBootJarFragmentsForPlatformBootclasspath = fmt.Sprintf(` { apex: "%[1]s", - module: "%[1]s-bootclasspathfragment", + module: "%[1]s-bootclasspath-fragment", }, { apex: "%[2]s", - module: "%[2]s-bootclasspathfragment", + module: "%[2]s-bootclasspath-fragment", }, `, "com.android.foo", "com.android.bar") @@ -64,15 +75,22 @@ var ApexBootJarDexJarPaths = []string{ "out/soong/.intermediates/packages/modules/com.android.foo/framework-foo/android_common_apex10000/aligned/framework-foo.jar", } -func prepareApexBootJarModule(apexName string, moduleName string) android.FixturePreparer { +func PrepareApexBootJarModule(apexName string, moduleName string) android.FixturePreparer { moduleSourceDir := fmt.Sprintf("packages/modules/%s", apexName) + fragmentName := apexName+"-bootclasspath-fragment" + imageNameProp := "" + if apexName == "com.android.art" { + fragmentName = "art-bootclasspath-fragment" + imageNameProp = `image_name: "art",` + } + return android.GroupFixturePreparers( android.FixtureAddTextFile(moduleSourceDir+"/Android.bp", fmt.Sprintf(` apex { name: "%[1]s", key: "%[1]s.key", bootclasspath_fragments: [ - "%[1]s-bootclasspathfragment", + "%[3]s", ], updatable: false, } @@ -84,7 +102,8 @@ func prepareApexBootJarModule(apexName string, moduleName string) android.Fixtur } bootclasspath_fragment { - name: "%[1]s-bootclasspathfragment", + name: "%[3]s", + %[4]s contents: ["%[2]s"], apex_available: ["%[1]s"], hidden_api: { @@ -100,7 +119,7 @@ func prepareApexBootJarModule(apexName string, moduleName string) android.Fixtur compile_dex: true, apex_available: ["%[1]s"], } - `, apexName, moduleName)), + `, apexName, moduleName, fragmentName, imageNameProp)), android.FixtureMergeMockFs(android.MockFS{ fmt.Sprintf("%s/apex_manifest.json", moduleSourceDir): nil, fmt.Sprintf("%s/%s.avbpubkey", moduleSourceDir, apexName): nil, @@ -192,7 +211,7 @@ func CheckArtBootImageConfig(t *testing.T, result *android.TestResult) { // getArtImageConfig gets the ART bootImageConfig that was created during the test. func getArtImageConfig(result *android.TestResult) *bootImageConfig { pathCtx := &android.TestPathContext{TestResult: result} - imageConfig := artBootImageConfig(pathCtx) + imageConfig := genBootImageConfigs(pathCtx)["art"] return imageConfig } @@ -210,15 +229,15 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b symbolsDir: "out/soong/dexpreopt_arm64/dex_artjars_unstripped", installDir: "apex/art_boot_images/javalib", profileInstallPathInApex: "etc/boot-image.prof", - modules: android.CreateTestConfiguredJarList([]string{"com.android.art:core1", "com.android.art:core2"}), - dexPaths: []string{"out/soong/dexpreopt_arm64/dex_artjars_input/core1.jar", "out/soong/dexpreopt_arm64/dex_artjars_input/core2.jar"}, - dexPathsDeps: []string{"out/soong/dexpreopt_arm64/dex_artjars_input/core1.jar", "out/soong/dexpreopt_arm64/dex_artjars_input/core2.jar"}, + modules: android.CreateTestConfiguredJarList([]string{"com.android.art:core1", "com.android.art:core2", "platform:extra1"}), + dexPaths: []string{"out/soong/dexpreopt_arm64/dex_artjars_input/core1.jar", "out/soong/dexpreopt_arm64/dex_artjars_input/core2.jar", "out/soong/dexpreopt_arm64/dex_artjars_input/extra1.jar"}, + dexPathsDeps: []string{"out/soong/dexpreopt_arm64/dex_artjars_input/core1.jar", "out/soong/dexpreopt_arm64/dex_artjars_input/core2.jar", "out/soong/dexpreopt_arm64/dex_artjars_input/extra1.jar"}, zip: "out/soong/dexpreopt_arm64/dex_artjars/art.zip", variants: []*expectedVariant{ { archType: android.Arm64, - dexLocations: []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"}, - dexLocationsDeps: []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"}, + dexLocations: []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar", "/system/framework/extra1.jar"}, + dexLocationsDeps: []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar", "/system/framework/extra1.jar"}, imagePathOnHost: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art", imagePathOnDevice: "/apex/art_boot_images/javalib/arm64/boot.art", imagesDeps: []string{ @@ -228,6 +247,9 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art", "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat", "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex", + "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.art", + "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.oat", + "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.vdex", }, installs: []normalizedInstall{ { @@ -246,6 +268,14 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat", to: "/apex/art_boot_images/javalib/arm64/boot-core2.oat", }, + { + from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.art", + to: "/apex/art_boot_images/javalib/arm64/boot-extra1.art", + }, + { + from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.oat", + to: "/apex/art_boot_images/javalib/arm64/boot-extra1.oat", + }, }, vdexInstalls: []normalizedInstall{ { @@ -256,6 +286,10 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex", to: "/apex/art_boot_images/javalib/arm64/boot-core2.vdex", }, + { + from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.vdex", + to: "/apex/art_boot_images/javalib/arm64/boot-extra1.vdex", + }, }, unstrippedInstalls: []normalizedInstall{ { @@ -266,13 +300,17 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat", to: "/apex/art_boot_images/javalib/arm64/boot-core2.oat", }, + { + from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-extra1.oat", + to: "/apex/art_boot_images/javalib/arm64/boot-extra1.oat", + }, }, licenseMetadataFile: expectedLicenseMetadataFile, }, { archType: android.Arm, - dexLocations: []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"}, - dexLocationsDeps: []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"}, + dexLocations: []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar", "/system/framework/extra1.jar"}, + dexLocationsDeps: []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar", "/system/framework/extra1.jar"}, imagePathOnHost: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art", imagePathOnDevice: "/apex/art_boot_images/javalib/arm/boot.art", imagesDeps: []string{ @@ -282,6 +320,9 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art", "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat", "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex", + "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.art", + "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.oat", + "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.vdex", }, installs: []normalizedInstall{ { @@ -300,6 +341,14 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat", to: "/apex/art_boot_images/javalib/arm/boot-core2.oat", }, + { + from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.art", + to: "/apex/art_boot_images/javalib/arm/boot-extra1.art", + }, + { + from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.oat", + to: "/apex/art_boot_images/javalib/arm/boot-extra1.oat", + }, }, vdexInstalls: []normalizedInstall{ { @@ -310,6 +359,10 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex", to: "/apex/art_boot_images/javalib/arm/boot-core2.vdex", }, + { + from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.vdex", + to: "/apex/art_boot_images/javalib/arm/boot-extra1.vdex", + }, }, unstrippedInstalls: []normalizedInstall{ { @@ -320,13 +373,17 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat", to: "/apex/art_boot_images/javalib/arm/boot-core2.oat", }, + { + from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-extra1.oat", + to: "/apex/art_boot_images/javalib/arm/boot-extra1.oat", + }, }, licenseMetadataFile: expectedLicenseMetadataFile, }, { archType: android.X86_64, - dexLocations: []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"}, - dexLocationsDeps: []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"}, + dexLocations: []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar", "host/linux-x86/system/framework/extra1.jar"}, + dexLocationsDeps: []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar", "host/linux-x86/system/framework/extra1.jar"}, imagePathOnHost: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art", imagePathOnDevice: "/apex/art_boot_images/javalib/x86_64/boot.art", imagesDeps: []string{ @@ -336,6 +393,9 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art", "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat", "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex", + "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.art", + "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.oat", + "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.vdex", }, installs: []normalizedInstall{ { @@ -352,6 +412,13 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat", to: "/apex/art_boot_images/javalib/x86_64/boot-core2.oat", }, + { + from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.art", + to: "/apex/art_boot_images/javalib/x86_64/boot-extra1.art", + }, { + from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.oat", + to: "/apex/art_boot_images/javalib/x86_64/boot-extra1.oat", + }, }, vdexInstalls: []normalizedInstall{ { @@ -362,6 +429,10 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex", to: "/apex/art_boot_images/javalib/x86_64/boot-core2.vdex", }, + { + from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.vdex", + to: "/apex/art_boot_images/javalib/x86_64/boot-extra1.vdex", + }, }, unstrippedInstalls: []normalizedInstall{ { @@ -372,13 +443,17 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat", to: "/apex/art_boot_images/javalib/x86_64/boot-core2.oat", }, + { + from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.oat", + to: "/apex/art_boot_images/javalib/x86_64/boot-extra1.oat", + }, }, licenseMetadataFile: expectedLicenseMetadataFile, }, { archType: android.X86, - dexLocations: []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"}, - dexLocationsDeps: []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"}, + dexLocations: []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar", "host/linux-x86/system/framework/extra1.jar"}, + dexLocationsDeps: []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar", "host/linux-x86/system/framework/extra1.jar"}, imagePathOnHost: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art", imagePathOnDevice: "/apex/art_boot_images/javalib/x86/boot.art", imagesDeps: []string{ @@ -388,6 +463,9 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art", "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat", "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex", + "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.art", + "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.oat", + "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.vdex", }, installs: []normalizedInstall{ { @@ -404,6 +482,13 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat", to: "/apex/art_boot_images/javalib/x86/boot-core2.oat", }, + { + from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.art", + to: "/apex/art_boot_images/javalib/x86/boot-extra1.art", + }, { + from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.oat", + to: "/apex/art_boot_images/javalib/x86/boot-extra1.oat", + }, }, vdexInstalls: []normalizedInstall{ { @@ -414,6 +499,10 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex", to: "/apex/art_boot_images/javalib/x86/boot-core2.vdex", }, + { + from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.vdex", + to: "/apex/art_boot_images/javalib/x86/boot-extra1.vdex", + }, }, unstrippedInstalls: []normalizedInstall{ { @@ -424,6 +513,10 @@ func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated b from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat", to: "/apex/art_boot_images/javalib/x86/boot-core2.oat", }, + { + from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.oat", + to: "/apex/art_boot_images/javalib/x86/boot-extra1.oat", + }, }, licenseMetadataFile: expectedLicenseMetadataFile, }, @@ -805,8 +898,8 @@ func checkFrameworkBootImageConfig(t *testing.T, result *android.TestResult, mut }, }, profileInstalls: []normalizedInstall{ + {from: "out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof", to: "/system/etc/boot-image.prof"}, {from: "out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof", to: "/system/etc/boot-image.bprof"}, - {from: "out/soong/dexpreopt_arm64/dex_bootjars/boot.prof", to: "/system/etc/boot-image.prof"}, }, profileLicenseMetadataFile: expectedLicenseMetadataFile, } @@ -1136,7 +1229,6 @@ func nestedCheckBootImageConfig(t *testing.T, imageConfig *bootImageConfig, expe android.AssertPathRelativeToTopEquals(t, "dir", expected.dir, imageConfig.dir) android.AssertPathRelativeToTopEquals(t, "symbolsDir", expected.symbolsDir, imageConfig.symbolsDir) android.AssertStringEquals(t, "installDir", expected.installDir, imageConfig.installDir) - android.AssertStringEquals(t, "profileInstallPathInApex", expected.profileInstallPathInApex, imageConfig.profileInstallPathInApex) android.AssertDeepEquals(t, "modules", expected.modules, imageConfig.modules) android.AssertPathsRelativeToTopEquals(t, "dexPaths", expected.dexPaths, imageConfig.dexPaths.Paths()) android.AssertPathsRelativeToTopEquals(t, "dexPathsDeps", expected.dexPathsDeps, imageConfig.dexPathsDeps.Paths()) @@ -1195,10 +1287,10 @@ DEXPREOPT_BOOTCLASSPATH_DEX_FILES=out/soong/dexpreopt_arm64/dex_bootjars_input/c DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS=/apex/com.android.art/javalib/core1.jar /apex/com.android.art/javalib/core2.jar /system/framework/framework.jar DEXPREOPT_BOOT_JARS_MODULES=com.android.art:core1:com.android.art:core2:platform:framework DEXPREOPT_GEN=out/host/linux-x86/bin/dexpreopt_gen -DEXPREOPT_IMAGE_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art:/apex/art_boot_images/javalib/arm/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art:/apex/art_boot_images/javalib/arm/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat -DEXPREOPT_IMAGE_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art:/apex/art_boot_images/javalib/arm64/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art:/apex/art_boot_images/javalib/arm64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat -DEXPREOPT_IMAGE_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art:/apex/art_boot_images/javalib/x86/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art:/apex/art_boot_images/javalib/x86/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat -DEXPREOPT_IMAGE_BUILT_INSTALLED_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art:/apex/art_boot_images/javalib/x86_64/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat:/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art:/apex/art_boot_images/javalib/x86_64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat:/apex/art_boot_images/javalib/x86_64/boot-core2.oat +DEXPREOPT_IMAGE_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art:/apex/art_boot_images/javalib/arm/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art:/apex/art_boot_images/javalib/arm/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.art:/apex/art_boot_images/javalib/arm/boot-extra1.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.oat:/apex/art_boot_images/javalib/arm/boot-extra1.oat +DEXPREOPT_IMAGE_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art:/apex/art_boot_images/javalib/arm64/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art:/apex/art_boot_images/javalib/arm64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.art:/apex/art_boot_images/javalib/arm64/boot-extra1.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.oat:/apex/art_boot_images/javalib/arm64/boot-extra1.oat +DEXPREOPT_IMAGE_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art:/apex/art_boot_images/javalib/x86/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art:/apex/art_boot_images/javalib/x86/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.art:/apex/art_boot_images/javalib/x86/boot-extra1.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.oat:/apex/art_boot_images/javalib/x86/boot-extra1.oat +DEXPREOPT_IMAGE_BUILT_INSTALLED_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art:/apex/art_boot_images/javalib/x86_64/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat:/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art:/apex/art_boot_images/javalib/x86_64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat:/apex/art_boot_images/javalib/x86_64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.art:/apex/art_boot_images/javalib/x86_64/boot-extra1.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.oat:/apex/art_boot_images/javalib/x86_64/boot-extra1.oat DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_arm=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot.art:/system/framework/arm/boot.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot.oat:/system/framework/arm/boot.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-core2.art:/system/framework/arm/boot-core2.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-core2.oat:/system/framework/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.art:/system/framework/arm/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.oat:/system/framework/arm/boot-framework.oat DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_arm64=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art:/system/framework/arm64/boot.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.oat:/system/framework/arm64/boot.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-core2.art:/system/framework/arm64/boot-core2.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-core2.oat:/system/framework/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.art:/system/framework/arm64/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.oat:/system/framework/arm64/boot-framework.oat DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_host_x86=out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot.art:/system/framework/x86/boot.art out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot.oat:/system/framework/x86/boot.oat out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-core2.art:/system/framework/x86/boot-core2.art out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-core2.oat:/system/framework/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art:/system/framework/x86/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat:/system/framework/x86/boot-framework.oat @@ -1207,10 +1299,10 @@ DEXPREOPT_IMAGE_BUILT_INSTALLED_mainline_arm=out/soong/dexpreopt_arm64/dex_mainl DEXPREOPT_IMAGE_BUILT_INSTALLED_mainline_arm64=out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art:/system/framework/arm64/boot-framework-foo.art out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.oat:/system/framework/arm64/boot-framework-foo.oat DEXPREOPT_IMAGE_BUILT_INSTALLED_mainline_host_x86=out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art:/system/framework/x86/boot-framework-foo.art out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.oat:/system/framework/x86/boot-framework-foo.oat DEXPREOPT_IMAGE_BUILT_INSTALLED_mainline_host_x86_64=out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art:/system/framework/x86_64/boot-framework-foo.art out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.oat:/system/framework/x86_64/boot-framework-foo.oat -DEXPREOPT_IMAGE_DEPS_art_arm=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex -DEXPREOPT_IMAGE_DEPS_art_arm64=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex -DEXPREOPT_IMAGE_DEPS_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex -DEXPREOPT_IMAGE_DEPS_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex +DEXPREOPT_IMAGE_DEPS_art_arm=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.vdex +DEXPREOPT_IMAGE_DEPS_art_arm64=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.vdex +DEXPREOPT_IMAGE_DEPS_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.vdex +DEXPREOPT_IMAGE_DEPS_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.vdex DEXPREOPT_IMAGE_DEPS_boot_arm=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot.vdex out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-core2.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-core2.vdex out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.vdex DEXPREOPT_IMAGE_DEPS_boot_arm64=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.vdex out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-core2.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-core2.vdex out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.vdex DEXPREOPT_IMAGE_DEPS_boot_host_x86=out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot.art out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot.oat out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot.vdex out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-core2.art out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-core2.vdex out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex @@ -1223,14 +1315,14 @@ DEXPREOPT_IMAGE_LICENSE_METADATA_art_arm=%[1]s DEXPREOPT_IMAGE_LICENSE_METADATA_art_arm64=%[1]s DEXPREOPT_IMAGE_LICENSE_METADATA_art_host_x86=%[1]s DEXPREOPT_IMAGE_LICENSE_METADATA_art_host_x86_64=%[1]s -DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic -DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic -DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic -DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86_64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic -DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_arm=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic -DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_arm64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic -DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_host_x86=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic -DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_host_x86_64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic +DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic +DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm64=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic +DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic +DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86_64=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic +DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_arm=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic +DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_arm64=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic +DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_host_x86=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic +DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_host_x86_64=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEart=/apex/art_boot_images/javalib/boot.art DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEboot=/system/framework/boot.art DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEmainline=/system/framework/boot.art:/system/framework/boot-framework-foo.art @@ -1238,12 +1330,12 @@ DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTart=out/soong/dexpreopt_arm64/dex_artjars/andro DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTboot=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot.art DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTmainline=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot.art:out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/boot-framework-foo.art DEXPREOPT_IMAGE_NAMES=art boot mainline -DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED=out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof:/system/etc/boot-image.bprof out/soong/dexpreopt_arm64/dex_bootjars/boot.prof:/system/etc/boot-image.prof -DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic -DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat -DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat -DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat -DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat:/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat:/apex/art_boot_images/javalib/x86_64/boot-core2.oat +DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED=out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof:/system/etc/boot-image.prof out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof:/system/etc/boot-image.bprof +DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic +DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-extra1.oat:/apex/art_boot_images/javalib/arm/boot-extra1.oat +DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-extra1.oat:/apex/art_boot_images/javalib/arm64/boot-extra1.oat +DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.oat:/apex/art_boot_images/javalib/x86/boot-extra1.oat +DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat:/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat:/apex/art_boot_images/javalib/x86_64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.oat:/apex/art_boot_images/javalib/x86_64/boot-extra1.oat DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_arm=out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm/boot.oat:/system/framework/arm/boot.oat out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm/boot-core2.oat:/system/framework/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm/boot-framework.oat:/system/framework/arm/boot-framework.oat DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_arm64=out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot.oat:/system/framework/arm64/boot.oat out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-core2.oat:/system/framework/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-framework.oat:/system/framework/arm64/boot-framework.oat DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_host_x86=out/soong/dexpreopt_arm64/dex_bootjars_unstripped/linux_glibc/system/framework/x86/boot.oat:/system/framework/x86/boot.oat out/soong/dexpreopt_arm64/dex_bootjars_unstripped/linux_glibc/system/framework/x86/boot-core2.oat:/system/framework/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars_unstripped/linux_glibc/system/framework/x86/boot-framework.oat:/system/framework/x86/boot-framework.oat @@ -1252,10 +1344,10 @@ DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_mainline_arm=out/soong/dexpreopt_arm6 DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_mainline_arm64=out/soong/dexpreopt_arm64/dex_mainlinejars_unstripped/android/system/framework/arm64/boot-framework-foo.oat:/system/framework/arm64/boot-framework-foo.oat DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_mainline_host_x86=out/soong/dexpreopt_arm64/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86/boot-framework-foo.oat:/system/framework/x86/boot-framework-foo.oat DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_mainline_host_x86_64=out/soong/dexpreopt_arm64/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86_64/boot-framework-foo.oat:/system/framework/x86_64/boot-framework-foo.oat -DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex:/apex/art_boot_images/javalib/arm/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex:/apex/art_boot_images/javalib/arm/boot-core2.vdex -DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex:/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex:/apex/art_boot_images/javalib/arm64/boot-core2.vdex -DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex:/apex/art_boot_images/javalib/x86/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex:/apex/art_boot_images/javalib/x86/boot-core2.vdex -DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex:/apex/art_boot_images/javalib/x86_64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex:/apex/art_boot_images/javalib/x86_64/boot-core2.vdex +DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex:/apex/art_boot_images/javalib/arm/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex:/apex/art_boot_images/javalib/arm/boot-core2.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.vdex:/apex/art_boot_images/javalib/arm/boot-extra1.vdex +DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex:/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex:/apex/art_boot_images/javalib/arm64/boot-core2.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.vdex:/apex/art_boot_images/javalib/arm64/boot-extra1.vdex +DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex:/apex/art_boot_images/javalib/x86/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex:/apex/art_boot_images/javalib/x86/boot-core2.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.vdex:/apex/art_boot_images/javalib/x86/boot-extra1.vdex +DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex:/apex/art_boot_images/javalib/x86_64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex:/apex/art_boot_images/javalib/x86_64/boot-core2.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.vdex:/apex/art_boot_images/javalib/x86_64/boot-extra1.vdex DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_arm=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot.vdex:/system/framework/arm/boot.vdex out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-core2.vdex:/system/framework/arm/boot-core2.vdex out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.vdex:/system/framework/arm/boot-framework.vdex DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_arm64=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.vdex:/system/framework/arm64/boot.vdex out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-core2.vdex:/system/framework/arm64/boot-core2.vdex out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.vdex:/system/framework/arm64/boot-framework.vdex DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_host_x86=out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot.vdex:/system/framework/x86/boot.vdex out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-core2.vdex:/system/framework/x86/boot-core2.vdex out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex:/system/framework/x86/boot-framework.vdex diff --git a/java/droidstubs.go b/java/droidstubs.go index 151c94a43..bb2388f96 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -525,8 +525,7 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":") } - cmd.Flag("--no-banner"). - Flag("--color"). + cmd.Flag("--color"). Flag("--quiet"). Flag("--format=v2"). FlagWithArg("--repeat-errors-max ", "10"). 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_modular.go b/java/hiddenapi_modular.go index c6b921bb2..f31f5d1a8 100644 --- a/java/hiddenapi_modular.go +++ b/java/hiddenapi_modular.go @@ -1236,7 +1236,6 @@ func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, suffix s rule := android.NewRuleBuilder(pctx, ctx) rule.Command(). BuiltTool("metalava"). - Flag("--no-banner"). Inputs(removedTxtFiles). FlagWithOutput("--dex-api ", output) rule.Build("modular-hiddenapi-removed-dex-signatures"+suffix, "modular hiddenapi removed dex signatures"+suffix) diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index d4ee4fc9f..714634f58 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -166,7 +166,7 @@ func isModuleInConfiguredList(ctx android.BaseModuleContext, module android.Modu // Now match the apex part of the boot image configuration. requiredApex := configuredBootJars.Apex(index) - if requiredApex == "platform" || requiredApex == "system_ext" { + if android.IsConfiguredJarForPlatform(requiredApex) { if len(apexInfo.InApexVariants) != 0 { // A platform variant is required but this is for an apex so ignore it. return false diff --git a/java/java.go b/java/java.go index 50d48ab6d..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{}) @@ -676,6 +683,8 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.minSdkVersion = j.MinSdkVersion(ctx) j.maxSdkVersion = j.MaxSdkVersion(ctx) + j.stem = proptools.StringDefault(j.overridableDeviceProperties.Stem, ctx.ModuleName()) + apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) if !apexInfo.IsForPlatform() { j.hideApexVariantFromMake = true @@ -690,7 +699,7 @@ 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()) @@ -728,6 +737,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { } }) j.exportedProguardFlagFiles = android.FirstUniquePaths(j.exportedProguardFlagFiles) + } func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) { @@ -1468,6 +1478,8 @@ func (j *Binary) HostToolPath() android.OptionalPath { } func (j *Binary) GenerateAndroidBuildActions(ctx android.ModuleContext) { + j.stem = proptools.StringDefault(j.overridableDeviceProperties.Stem, ctx.ModuleName()) + if ctx.Arch().ArchType == android.Common { // Compile the jar if j.binaryProperties.Main_class != nil { @@ -1716,8 +1728,7 @@ func metalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder, FlagWithArg("-encoding ", "UTF-8"). FlagWithInputList("--source-files ", srcs, " ") - cmd.Flag("--no-banner"). - Flag("--color"). + cmd.Flag("--color"). Flag("--quiet"). Flag("--format=v2"). Flag("--include-annotations"). @@ -1878,8 +1889,10 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { flags.javacFlags = strings.Join(al.properties.Javacflags, " ") flags.classpath = classpath(classPaths) + annoSrcJar := android.PathForModuleOut(ctx, ctx.ModuleName(), "anno.srcjar") + TransformJavaToClasses(ctx, al.stubsJarWithoutStaticLibs, 0, android.Paths{}, - android.Paths{al.stubsSrcJar}, flags, android.Paths{}) + android.Paths{al.stubsSrcJar}, annoSrcJar, flags, android.Paths{}) } builder := android.NewRuleBuilder(pctx, ctx) @@ -1911,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 }) } @@ -2232,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 }) } @@ -2652,7 +2667,7 @@ func (ks *kytheExtractJavaSingleton) GenerateBuildActions(ctx android.SingletonC var Bool = proptools.Bool var BoolDefault = proptools.BoolDefault var String = proptools.String -var inList = android.InList +var inList = android.InList[string] // Add class loader context (CLC) of a given dependency to the current CLC. func addCLCFromDep(ctx android.ModuleContext, depModule android.Module, @@ -2766,11 +2781,12 @@ func (m *Library) convertJavaResourcesAttributes(ctx android.TopDownMutatorConte type javaCommonAttributes struct { *javaResourcesAttributes *kotlinAttributes - Srcs bazel.LabelListAttribute - Plugins bazel.LabelListAttribute - Javacopts bazel.StringListAttribute - Sdk_version bazel.StringAttribute - Java_version bazel.StringAttribute + Srcs bazel.LabelListAttribute + Plugins bazel.LabelListAttribute + Javacopts bazel.StringListAttribute + Sdk_version bazel.StringAttribute + Java_version bazel.StringAttribute + Errorprone_force_enable bazel.BoolAttribute } type javaDependencyLabels struct { @@ -2803,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 @@ -2819,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) - } } } @@ -2841,6 +2846,7 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) javaSrcPartition := "java" protoSrcPartition := "proto" + xsdSrcPartition := "xsd" logtagSrcPartition := "logtag" aidlSrcPartition := "aidl" kotlinPartition := "kotlin" @@ -2849,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"}}, }) @@ -2856,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( @@ -2909,29 +2918,38 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) }, ) - staticDeps.Add(&bazel.Label{Label: ":" + javaAidlLibName}) + staticDeps.Append(bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + javaAidlLibName})) } - var javacopts []string + var javacopts bazel.StringListAttribute //[]string + plugins := bazel.MakeLabelListAttribute( + android.BazelLabelForModuleDeps(ctx, m.properties.Plugins), + ) if m.properties.Javacflags != nil { - javacopts = append(javacopts, m.properties.Javacflags...) + javacopts = bazel.MakeStringListAttribute(m.properties.Javacflags) } epEnabled := m.properties.Errorprone.Enabled - //TODO(b/227504307) add configuration that depends on RUN_ERROR_PRONE environment variable - if Bool(epEnabled) { - javacopts = append(javacopts, m.properties.Errorprone.Javacflags...) + epJavacflags := m.properties.Errorprone.Javacflags + var errorproneForceEnable bazel.BoolAttribute + if epEnabled == nil { + //TODO(b/227504307) add configuration that depends on RUN_ERROR_PRONE environment variable + } else if *epEnabled { + plugins.Append(bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, m.properties.Errorprone.Extra_check_modules))) + javacopts.Append(bazel.MakeStringListAttribute(epJavacflags)) + errorproneForceEnable.Value = epEnabled + } else { + javacopts.Append(bazel.MakeStringListAttribute([]string{"-XepDisableAllChecks"})) } commonAttrs := &javaCommonAttributes{ Srcs: javaSrcs, javaResourcesAttributes: m.convertJavaResourcesAttributes(ctx), - Plugins: bazel.MakeLabelListAttribute( - android.BazelLabelForModuleDeps(ctx, m.properties.Plugins), - ), - Javacopts: bazel.MakeStringListAttribute(javacopts), - Java_version: bazel.StringAttribute{Value: m.properties.Java_version}, - Sdk_version: bazel.StringAttribute{Value: m.deviceProperties.Sdk_version}, + Plugins: plugins, + Javacopts: javacopts, + Java_version: bazel.StringAttribute{Value: m.properties.Java_version}, + Sdk_version: bazel.StringAttribute{Value: m.deviceProperties.Sdk_version}, + Errorprone_force_enable: errorproneForceEnable, } for axis, configToProps := range archVariantProps { @@ -2955,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 @@ -2970,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{ @@ -3140,6 +3160,7 @@ func javaBinaryHostBp2Build(ctx android.TopDownMutatorContext, m *Binary) { type javaTestHostAttributes struct { *javaCommonAttributes + Srcs bazel.LabelListAttribute Deps bazel.LabelListAttribute Runtime_deps bazel.LabelListAttribute } @@ -3176,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) } @@ -3290,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/java_test.go b/java/java_test.go index 473830464..dd9867704 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -2351,3 +2351,22 @@ func TestJavaExcludeStaticLib(t *testing.T) { `stable.core.platform.api.stubs`, }) } + +func TestJavaLibraryWithResourcesStem(t *testing.T) { + ctx, _ := testJavaWithFS(t, ` + java_library { + name: "foo", + java_resource_dirs: ["test-jar"], + stem: "test", + } + `, + map[string][]byte{ + "test-jar/test/resource.txt": nil, + }) + + m := ctx.ModuleForTests("foo", "android_common") + outputs := fmt.Sprint(m.AllOutputs()) + if !strings.Contains(outputs, "test.jar") { + t.Errorf("Module output does not contain expected jar %s", "test.jar") + } +} diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index 0d4db7ca1..a4bba486d 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -123,15 +123,15 @@ func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpM } func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) { - // Add dependencies on all the modules configured in the "art" boot image. - artImageConfig := genBootImageConfigs(ctx)[artBootImageName] - addDependenciesOntoBootImageModules(ctx, artImageConfig.modules, platformBootclasspathArtBootJarDepTag) + // Add dependencies on all the ART jars. + global := dexpreopt.GetGlobalConfig(ctx) + addDependenciesOntoBootImageModules(ctx, global.ArtApexJars, platformBootclasspathArtBootJarDepTag) - // Add dependencies on all the non-updatable module configured in the "boot" boot image. That does - // not include modules configured in the "art" boot image. + // Add dependencies on all the non-updatable jars, which are on the platform or in non-updatable + // APEXes. addDependenciesOntoBootImageModules(ctx, b.platformJars(ctx), platformBootclasspathBootJarDepTag) - // Add dependencies on all the apex jars. + // Add dependencies on all the updatable jars, except the ART jars. apexJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag) @@ -186,7 +186,6 @@ func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.Mo bootDexJarByModule := b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments) buildRuleForBootJarsPackageCheck(ctx, bootDexJarByModule) - b.generateBootImageBuildActions(ctx) b.copyApexBootJarsForAppsDexpreopt(ctx, apexModules) } @@ -218,7 +217,8 @@ func (b *platformBootclasspathModule) configuredJars(ctx android.ModuleContext) } func (b *platformBootclasspathModule) platformJars(ctx android.PathContext) android.ConfiguredJarList { - return defaultBootImageConfig(ctx).modules.RemoveList(artBootImageConfig(ctx).modules) + global := dexpreopt.GetGlobalConfig(ctx) + return global.BootJars.RemoveList(global.ArtApexJars) } // checkPlatformModules ensures that the non-updatable modules supplied are not part of an @@ -399,78 +399,9 @@ func (b *platformBootclasspathModule) generateHiddenApiMakeVars(ctx android.Make ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", b.hiddenAPIFlagsCSV.String()) } -// generateBootImageBuildActions generates ninja rules related to the boot image creation. -func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.ModuleContext) { - // Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars - // GenerateSingletonBuildActions method as it cannot create it for itself. - dexpreopt.GetGlobalSoongConfig(ctx) - - global := dexpreopt.GetGlobalConfig(ctx) - if !shouldBuildBootImages(ctx.Config(), global) { - return - } - - frameworkBootImageConfig := defaultBootImageConfig(ctx) - bootFrameworkProfileRule(ctx, frameworkBootImageConfig) - b.generateBootImage(ctx, frameworkBootImageName) - b.generateBootImage(ctx, mainlineBootImageName) - dumpOatRules(ctx, frameworkBootImageConfig) -} - -func (b *platformBootclasspathModule) generateBootImage(ctx android.ModuleContext, imageName string) { - imageConfig := genBootImageConfigs(ctx)[imageName] - - modules := b.getModulesForImage(ctx, imageConfig) - - // Copy module dex jars to their predefined locations. - bootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, modules) - copyBootJarsToPredefinedLocations(ctx, bootDexJarsByModule, imageConfig.dexPathsByModule) - - // Build a profile for the image config and then use that to build the boot image. - profile := bootImageProfileRule(ctx, imageConfig) - - // If dexpreopt of boot image jars should be skipped, generate only a profile. - global := dexpreopt.GetGlobalConfig(ctx) - if global.DisablePreoptBootImages { - return - } - - // Build boot image files for the android variants. - androidBootImageFiles := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile) - - // Zip the android variant boot image files up. - buildBootImageZipInPredefinedLocation(ctx, imageConfig, androidBootImageFiles.byArch) - - // Build boot image files for the host variants. There are use directly by ART host side tests. - buildBootImageVariantsForBuildOs(ctx, imageConfig, profile) -} - // Copy apex module dex jars to their predefined locations. They will be used for dexpreopt for apps. func (b *platformBootclasspathModule) copyApexBootJarsForAppsDexpreopt(ctx android.ModuleContext, apexModules []android.Module) { config := GetApexBootConfig(ctx) apexBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, apexModules) copyBootJarsToPredefinedLocations(ctx, apexBootDexJarsByModule, config.dexPathsByModule) } - -func (b *platformBootclasspathModule) getModulesForImage(ctx android.ModuleContext, imageConfig *bootImageConfig) []android.Module { - modules := make([]android.Module, 0, imageConfig.modules.Len()) - for i := 0; i < imageConfig.modules.Len(); i++ { - found := false - for _, module := range b.configuredModules { - name := android.RemoveOptionalPrebuiltPrefix(module.Name()) - if name == imageConfig.modules.Jar(i) { - modules = append(modules, module) - found = true - break - } - } - if !found && !ctx.Config().AllowMissingDependencies() { - ctx.ModuleErrorf( - "Boot image '%s' module '%s' not added as a dependency of platform_bootclasspath", - imageConfig.name, - imageConfig.modules.Jar(i)) - return []android.Module{} - } - } - return modules -} diff --git a/rust/binary.go b/rust/binary.go index 2de92c17f..e6f153996 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -158,9 +158,6 @@ func (binary *binaryDecorator) autoDep(ctx android.BottomUpMutatorContext) autoD // Binaries default to dylib dependencies for device, rlib for host. if binary.preferRlib() { return rlibAutoDep - } else if mod, ok := ctx.Module().(*Module); ok && mod.InVendor() { - // Vendor Rust binaries should prefer rlibs. - return rlibAutoDep } else if ctx.Device() { return dylibAutoDep } else { @@ -171,8 +168,6 @@ func (binary *binaryDecorator) autoDep(ctx android.BottomUpMutatorContext) autoD func (binary *binaryDecorator) stdLinkage(ctx *depsContext) RustLinkage { if binary.preferRlib() { return RlibLinkage - } else if ctx.RustModule().InVendor() { - return RlibLinkage } return binary.baseCompiler.stdLinkage(ctx) } diff --git a/rust/bindgen.go b/rust/bindgen.go index 7dc1b4b10..59585aaf8 100644 --- a/rust/bindgen.go +++ b/rust/bindgen.go @@ -29,7 +29,7 @@ var ( defaultBindgenFlags = []string{""} // bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures. - bindgenClangVersion = "clang-r487747c" + bindgenClangVersion = "clang-r498229" _ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string { if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" { 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 50bf02a4a..c2e250cf0 100644 --- a/rust/image.go +++ b/rust/image.go @@ -220,9 +220,6 @@ func (mod *Module) SetImageVariation(ctx android.BaseModuleContext, variant stri } func (mod *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { - // Rust does not support installing to the product image yet. - vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific() - if Bool(mod.VendorProperties.Double_loadable) { mctx.PropertyErrorf("double_loadable", "Rust modules do not yet support double loading") @@ -232,16 +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 vendorSpecific { - if lib, ok := mod.compiler.(libraryInterface); ok && lib.buildDylib() { - mctx.PropertyErrorf("vendor", "Vendor-only dylibs are not yet supported, use rust_library_rlib.") - } - } - 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/library.go b/rust/library.go index 331763a50..3f480a259 100644 --- a/rust/library.go +++ b/rust/library.go @@ -21,7 +21,6 @@ import ( "android/soong/android" "android/soong/cc" - "android/soong/snapshot" ) var ( @@ -236,10 +235,7 @@ func (library *libraryDecorator) setSource() { } func (library *libraryDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep { - if ctx.Module().(*Module).InVendor() { - // Vendor modules should statically link libstd. - return rlibAutoDep - } else if library.preferRlib() { + if library.preferRlib() { return rlibAutoDep } else if library.rlib() || library.static() { return rlibAutoDep @@ -251,10 +247,7 @@ func (library *libraryDecorator) autoDep(ctx android.BottomUpMutatorContext) aut } func (library *libraryDecorator) stdLinkage(ctx *depsContext) RustLinkage { - if ctx.RustModule().InVendor() { - // Vendor modules should statically link libstd. - return RlibLinkage - } else if library.static() || library.MutatedProperties.VariantIsStaticStd { + if library.static() || library.MutatedProperties.VariantIsStaticStd { return RlibLinkage } else if library.baseCompiler.preferRlib() { return RlibLinkage @@ -693,24 +686,6 @@ func LibraryMutator(mctx android.BottomUpMutatorContext) { v.(*Module).Disable() } - variation := v.(*Module).ModuleBase.ImageVariation().Variation - if strings.HasPrefix(variation, cc.VendorVariationPrefix) { - // TODO(b/204303985) - // Disable vendor dylibs until they are supported - v.(*Module).Disable() - } - - if strings.HasPrefix(variation, cc.VendorVariationPrefix) && - m.HasVendorVariant() && - !snapshot.IsVendorProprietaryModule(mctx) && - strings.TrimPrefix(variation, cc.VendorVariationPrefix) == mctx.DeviceConfig().VndkVersion() { - - // cc.MutateImage runs before LibraryMutator, so vendor variations which are meant for rlibs only are - // produced for Dylibs; however, dylibs should not be enabled for boardVndkVersion for - // non-vendor proprietary modules. - v.(*Module).Disable() - } - case "source": v.(*Module).compiler.(libraryInterface).setSource() // The source variant does not produce any library. @@ -747,10 +722,9 @@ func LibstdMutator(mctx android.BottomUpMutatorContext) { dylib := modules[1].(*Module) rlib.compiler.(libraryInterface).setRlibStd() dylib.compiler.(libraryInterface).setDylibStd() - if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation || - strings.HasPrefix(dylib.ModuleBase.ImageVariation().Variation, cc.VendorVariationPrefix) { + if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation { // TODO(b/165791368) - // Disable rlibs that link against dylib-std on vendor and vendor ramdisk variations until those dylib + // Disable rlibs that link against dylib-std on vendor ramdisk variations until those dylib // variants are properly supported. dylib.Disable() } diff --git a/rust/rust.go b/rust/rust.go index e524c9fb6..05fceee36 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -43,6 +43,7 @@ func init() { android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel() }) + pctx.Import("android/soong/android") pctx.Import("android/soong/rust/config") pctx.ImportAs("cc_config", "android/soong/cc/config") android.InitRegistrationContext.RegisterParallelSingletonType("kythe_rust_extract", kytheExtractRustFactory) @@ -91,6 +92,8 @@ type BaseProperties struct { // Used by vendor snapshot to record dependencies from snapshot modules. SnapshotSharedLibs []string `blueprint:"mutated"` SnapshotStaticLibs []string `blueprint:"mutated"` + SnapshotRlibs []string `blueprint:"mutated"` + SnapshotDylibs []string `blueprint:"mutated"` // Make this module available when building for ramdisk. // On device without a dedicated recovery partition, the module is only @@ -258,6 +261,15 @@ func (mod *Module) Dylib() bool { return false } +func (mod *Module) RlibStd() bool { + if mod.compiler != nil { + if library, ok := mod.compiler.(libraryInterface); ok && library.rlib() { + return library.rlibStd() + } + } + panic(fmt.Errorf("RlibStd() called on non-rlib module: %q", mod.BaseModuleName())) +} + func (mod *Module) Rlib() bool { if mod.compiler != nil { if library, ok := mod.compiler.(libraryInterface); ok { @@ -1225,6 +1237,8 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } directDylibDeps = append(directDylibDeps, rustDep) mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, makeLibName) + mod.Properties.SnapshotDylibs = append(mod.Properties.SnapshotDylibs, cc.BaseLibName(depName)) + case rlibDepTag: rlib, ok := rustDep.compiler.(libraryInterface) @@ -1234,6 +1248,8 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } directRlibDeps = append(directRlibDeps, rustDep) mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, makeLibName) + mod.Properties.SnapshotRlibs = append(mod.Properties.SnapshotRlibs, cc.BaseLibName(depName)) + case procMacroDepTag: directProcMacroDeps = append(directProcMacroDeps, rustDep) mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName) @@ -1518,10 +1534,10 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { } // dylibs - actx.AddVariationDependencies( - append(commonDepVariations, []blueprint.Variation{ - {Mutator: "rust_libraries", Variation: dylibVariation}}...), - dylibDepTag, deps.Dylibs...) + dylibDepVariations := append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: dylibVariation}) + for _, lib := range deps.Dylibs { + addDylibDependency(actx, lib, mod, &snapshotInfo, dylibDepVariations, dylibDepTag) + } // rustlibs if deps.Rustlibs != nil && !mod.compiler.Disabled() { @@ -1536,8 +1552,11 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { // otherwise select the rlib variant. autoDepVariations := append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: autoDep.variation}) - if actx.OtherModuleDependencyVariantExists(autoDepVariations, lib) { - actx.AddVariationDependencies(autoDepVariations, autoDep.depTag, lib) + + replacementLib := cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Dylibs) + + if actx.OtherModuleDependencyVariantExists(autoDepVariations, replacementLib) { + addDylibDependency(actx, lib, mod, &snapshotInfo, autoDepVariations, autoDep.depTag) } else { // If there's no dylib dependency available, try to add the rlib dependency instead. addRlibDependency(actx, lib, mod, &snapshotInfo, rlibDepVariations) @@ -1549,16 +1568,14 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { if deps.Stdlibs != nil { if mod.compiler.stdLinkage(ctx) == RlibLinkage { for _, lib := range deps.Stdlibs { - depTag := rlibDepTag lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs) - actx.AddVariationDependencies(append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}...), - depTag, lib) + rlibDepTag, lib) } } else { - actx.AddVariationDependencies( - append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: "dylib"}), - dylibDepTag, deps.Stdlibs...) + for _, lib := range deps.Stdlibs { + addDylibDependency(actx, lib, mod, &snapshotInfo, dylibDepVariations, dylibDepTag) + } } } @@ -1636,6 +1653,11 @@ func addRlibDependency(actx android.BottomUpMutatorContext, lib string, mod *Mod actx.AddVariationDependencies(variations, rlibDepTag, lib) } +func addDylibDependency(actx android.BottomUpMutatorContext, lib string, mod *Module, snapshotInfo **cc.SnapshotInfo, variations []blueprint.Variation, depTag dependencyTag) { + lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, snapshotInfo, actx).Dylibs) + actx.AddVariationDependencies(variations, depTag, lib) +} + func BeginMutator(ctx android.BottomUpMutatorContext) { if mod, ok := ctx.Module().(*Module); ok && mod.Enabled() { mod.beginMutator(ctx) diff --git a/rust/rust_test.go b/rust/rust_test.go index 64f90b6e0..3f4e29676 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -79,14 +79,18 @@ func testRustVndk(t *testing.T, bp string) *android.TestContext { } const ( - sharedVendorVariant = "android_vendor.29_arm64_armv8-a_shared" - rlibVendorVariant = "android_vendor.29_arm64_armv8-a_rlib_rlib-std" - sharedRecoveryVariant = "android_recovery_arm64_armv8-a_shared" - rlibRecoveryVariant = "android_recovery_arm64_armv8-a_rlib_rlib-std" - binaryCoreVariant = "android_arm64_armv8-a" - binaryVendorVariant = "android_vendor.29_arm64_armv8-a" - binaryProductVariant = "android_product.29_arm64_armv8-a" - binaryRecoveryVariant = "android_recovery_arm64_armv8-a" + sharedVendorVariant = "android_vendor.29_arm64_armv8-a_shared" + rlibVendorVariant = "android_vendor.29_arm64_armv8-a_rlib_rlib-std" + rlibDylibStdVendorVariant = "android_vendor.29_arm64_armv8-a_rlib_rlib-std" + dylibVendorVariant = "android_vendor.29_arm64_armv8-a_dylib" + sharedRecoveryVariant = "android_recovery_arm64_armv8-a_shared" + rlibRecoveryVariant = "android_recovery_arm64_armv8-a_rlib_dylib-std" + rlibRlibStdRecoveryVariant = "android_recovery_arm64_armv8-a_rlib_rlib-std" + dylibRecoveryVariant = "android_recovery_arm64_armv8-a_dylib" + binaryCoreVariant = "android_arm64_armv8-a" + binaryVendorVariant = "android_vendor.29_arm64_armv8-a" + binaryProductVariant = "android_product.29_arm64_armv8-a" + binaryRecoveryVariant = "android_recovery_arm64_armv8-a" ) func testRustVndkFs(t *testing.T, bp string, fs android.MockFS) *android.TestContext { diff --git a/rust/snapshot_prebuilt.go b/rust/snapshot_prebuilt.go index 2f79cc5c3..32d391629 100644 --- a/rust/snapshot_prebuilt.go +++ b/rust/snapshot_prebuilt.go @@ -21,10 +21,6 @@ import ( "github.com/google/blueprint/proptools" ) -const ( - snapshotRlibSuffix = "_rlib." -) - type snapshotLibraryDecorator struct { cc.BaseSnapshotDecorator *libraryDecorator @@ -44,6 +40,8 @@ func init() { func registerRustSnapshotModules(ctx android.RegistrationContext) { cc.VendorSnapshotImageSingleton.RegisterAdditionalModule(ctx, "vendor_snapshot_rlib", VendorSnapshotRlibFactory) + cc.VendorSnapshotImageSingleton.RegisterAdditionalModule(ctx, + "vendor_snapshot_dylib", VendorSnapshotDylibFactory) cc.RecoverySnapshotImageSingleton.RegisterAdditionalModule(ctx, "recovery_snapshot_rlib", RecoverySnapshotRlibFactory) } @@ -77,12 +75,11 @@ func (library *snapshotLibraryDecorator) compile(ctx ModuleContext, flags Flags, variant = cc.SnapshotSharedSuffix } else if library.rlib() { variant = cc.SnapshotRlibSuffix + } else if library.dylib() { + variant = cc.SnapshotDylibSuffix } - if !library.dylib() { - // TODO(184042776): Remove this check when dylibs are supported in snapshots. - library.SetSnapshotAndroidMkSuffix(ctx, variant) - } + library.SetSnapshotAndroidMkSuffix(ctx, variant) if !library.MatchesWithDevice(ctx.DeviceConfig()) { return buildOutput{} @@ -107,6 +104,17 @@ func VendorSnapshotRlibFactory() android.Module { return module.Init() } +// vendor_snapshot_dylib is a special prebuilt dylib library which is auto-generated by +// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_dylib +// overrides the vendor variant of the rust dylib library with the same name, if BOARD_VNDK_VERSION +// is set. +func VendorSnapshotDylibFactory() android.Module { + module, prebuilt := snapshotLibraryFactory(cc.VendorSnapshotImageSingleton, cc.SnapshotDylibSuffix) + prebuilt.libraryDecorator.BuildOnlyDylib() + prebuilt.libraryDecorator.setNoStdlibs() + return module.Init() +} + func RecoverySnapshotRlibFactory() android.Module { module, prebuilt := snapshotLibraryFactory(cc.RecoverySnapshotImageSingleton, cc.SnapshotRlibSuffix) prebuilt.libraryDecorator.BuildOnlyRlib() diff --git a/rust/snapshot_utils.go b/rust/snapshot_utils.go index 8dabd9bf6..55c85e668 100644 --- a/rust/snapshot_utils.go +++ b/rust/snapshot_utils.go @@ -42,8 +42,7 @@ func (mod *Module) ExcludeFromRecoverySnapshot() bool { func (mod *Module) IsSnapshotLibrary() bool { if lib, ok := mod.compiler.(libraryInterface); ok { - // Rust-native dylibs are not snapshot supported yet. Only snapshot the rlib-std variants of rlibs. - return lib.shared() || lib.static() || (lib.rlib() && lib.rlibStd()) + return lib.shared() || lib.static() || lib.rlib() || lib.dylib() } return false } @@ -61,6 +60,14 @@ func (mod *Module) SnapshotStaticLibs() []string { return mod.Properties.SnapshotStaticLibs } +func (mod *Module) SnapshotRlibs() []string { + return mod.Properties.SnapshotRlibs +} + +func (mod *Module) SnapshotDylibs() []string { + return mod.Properties.SnapshotDylibs +} + func (mod *Module) Symlinks() []string { // TODO update this to return the list of symlinks when Rust supports defining symlinks return nil diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go index 2e7a33027..387d17043 100644 --- a/rust/vendor_snapshot_test.go +++ b/rust/vendor_snapshot_test.go @@ -48,15 +48,13 @@ func TestVendorSnapshotCapture(t *testing.T) { crate_name: "rustvendor_available", srcs: ["lib.rs"], vendor_available: true, - include_dirs: ["rust_headers/"], } - rust_library_rlib { + rust_library { name: "librustvendor", crate_name: "rustvendor", srcs: ["lib.rs"], vendor: true, - include_dirs: ["rust_headers/"], } rust_binary { @@ -116,7 +114,7 @@ func TestVendorSnapshotCapture(t *testing.T) { filepath.Join(staticDir, "libffivendor.a.json")) // For rlib libraries, all vendor:true and vendor_available modules (including VNDK) are captured. - rlibVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_rlib-std", archType, archVariant) + rlibVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_dylib-std", archType, archVariant) rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.rlib", rlibDir, rlibVariant) cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor", "librustvendor.rlib", rlibDir, rlibVariant) @@ -125,6 +123,25 @@ func TestVendorSnapshotCapture(t *testing.T) { jsonFiles = append(jsonFiles, filepath.Join(rlibDir, "librustvendor.rlib.json")) + // For rlib libraries, all rlib-std variants vendor:true and vendor_available modules (including VNDK) are captured. + rlibStdVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_rlib-std", archType, archVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.rlib-std.rlib", rlibDir, rlibStdVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor", "librustvendor.rlib-std.rlib", rlibDir, rlibStdVariant) + jsonFiles = append(jsonFiles, + filepath.Join(rlibDir, "librustvendor_available.rlib.json")) + jsonFiles = append(jsonFiles, + filepath.Join(rlibDir, "librustvendor.rlib.json")) + + // For dylib libraries, all vendor:true and vendor_available modules (including VNDK) are captured. + dylibVariant := fmt.Sprintf("android_vendor.29_%s_%s_dylib", archType, archVariant) + dylibDir := filepath.Join(snapshotVariantPath, archDir, "dylib") + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.dylib.so", dylibDir, dylibVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor", "librustvendor.dylib.so", dylibDir, dylibVariant) + jsonFiles = append(jsonFiles, + filepath.Join(dylibDir, "librustvendor_available.dylib.so.json")) + jsonFiles = append(jsonFiles, + filepath.Join(dylibDir, "librustvendor.dylib.so.json")) + // For binary executables, all vendor:true and vendor_available modules are captured. if archType == "arm64" { binaryVariant := fmt.Sprintf("android_vendor.29_%s_%s", archType, archVariant) @@ -209,21 +226,32 @@ func TestVendorSnapshotDirected(t *testing.T) { archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant) - rlibVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_rlib-std", archType, archVariant) + rlibVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_dylib-std", archType, archVariant) + rlibRlibStdVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_rlib-std", archType, archVariant) sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") + dylibVariant := fmt.Sprintf("android_vendor.29_%s_%s_dylib", archType, archVariant) + dylibDir := filepath.Join(snapshotVariantPath, archDir, "dylib") // Included modules cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.rlib", rlibDir, rlibVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.rlib-std.rlib", rlibDir, rlibRlibStdVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.dylib.so", dylibDir, dylibVariant) cc.CheckSnapshot(t, ctx, snapshotSingleton, "libffivendor_available", "libffivendor_available.so", sharedDir, sharedVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librustvendor_available.rlib.json")) + includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librustvendor_available.rlib-std.rlib.json")) + includeJsonFiles = append(includeJsonFiles, filepath.Join(dylibDir, "librustvendor_available.dylib.so.json")) includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libffivendor_available.so.json")) // Excluded modules. Modules not included in the directed vendor snapshot // are still include as fake modules. cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librustvendor_exclude", "librustvendor_exclude.rlib", rlibDir, rlibVariant) + cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librustvendor_exclude", "librustvendor_exclude.rlib-std.rlib", rlibDir, rlibRlibStdVariant) + cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librustvendor_exclude", "librustvendor_exclude.dylib.so", dylibDir, dylibVariant) cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "libffivendor_exclude", "libffivendor_exclude.so", sharedDir, sharedVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librustvendor_exclude.rlib.json")) + includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librustvendor_exclude.rlib-std.rlib.json")) + includeJsonFiles = append(includeJsonFiles, filepath.Join(dylibDir, "librustvendor_exclude.dylib.so.json")) includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libffivendor_exclude.so.json")) } @@ -274,7 +302,7 @@ func TestVendorSnapshotExclude(t *testing.T) { vendor_available: true, } - rust_library_rlib { + rust_library { name: "librust_exclude", crate_name: "rust_exclude", srcs: ["exclude.rs"], @@ -308,6 +336,14 @@ func TestVendorSnapshotExclude(t *testing.T) { cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_exclude", true, rlibVendorVariant) cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_available_exclude", true, rlibVendorVariant) + cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_include", false, rlibDylibStdVendorVariant) + cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_exclude", true, rlibDylibStdVendorVariant) + cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_available_exclude", true, rlibDylibStdVendorVariant) + + cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_include", false, dylibVendorVariant) + cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_exclude", true, dylibVendorVariant) + cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_available_exclude", true, dylibVendorVariant) + // Verify the content of the vendor snapshot. snapshotDir := "vendor-snapshot" @@ -327,14 +363,22 @@ func TestVendorSnapshotExclude(t *testing.T) { sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant) sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") - rlibVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_rlib-std", archType, archVariant) + + rlibVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_dylib-std", archType, archVariant) + rlibRlibStdVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_rlib-std", archType, archVariant) rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") + dylibVariant := fmt.Sprintf("android_vendor.29_%s_%s_dylib", archType, archVariant) + dylibDir := filepath.Join(snapshotVariantPath, archDir, "dylib") // Included modules cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json")) cc.CheckSnapshot(t, ctx, snapshotSingleton, "librust_include", "librust_include.rlib", rlibDir, rlibVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librust_include.rlib.json")) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librust_include", "librust_include.rlib-std.rlib", rlibDir, rlibRlibStdVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librust_include.rlib-std.rlib.json")) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librust_include", "librust_include.dylib.so", dylibDir, dylibVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(dylibDir, "librust_include.dylib.so.json")) // Excluded modules cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant) @@ -345,6 +389,12 @@ func TestVendorSnapshotExclude(t *testing.T) { excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librust_exclude.rlib.json")) cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librust_available_exclude", "librust_available_exclude.rlib", rlibDir, rlibVariant) excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librust_available_exclude.rlib.json")) + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librust_available_exclude", "librust_available_exclude.rlib-std.rlib", rlibDir, rlibRlibStdVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librust_available_exclude.rlib.rlib-std.json")) + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librust_exclude", "librust_exclude.dylib.so", dylibDir, dylibVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(dylibDir, "librust_exclude.dylib.so.json")) + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librust_available_exclude", "librust_available_exclude.dylib.so", dylibDir, dylibVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(dylibDir, "librust_available_exclude.dylib.so.json")) } // Verify that each json file for an included module has a rule. @@ -525,7 +575,7 @@ func TestVendorSnapshotUse(t *testing.T) { srcs: ["client.rs"], } - rust_library_rlib { + rust_library { name: "libclient_rust", crate_name: "client_rust", vendor: true, @@ -572,6 +622,11 @@ func TestVendorSnapshotUse(t *testing.T) { rlibs: [ "libstd", "librust_vendor_available", + "librust_vendor_available.rlib-std" + ], + dylibs: [ + "libstd", + "librust_vendor_available", ], binaries: [ "bin", @@ -600,6 +655,10 @@ func TestVendorSnapshotUse(t *testing.T) { "libstd", "librust_vendor_available", ], + dylibs: [ + "libstd", + "librust_vendor_available", + ], binaries: [ "bin32", ], @@ -679,6 +738,52 @@ func TestVendorSnapshotUse(t *testing.T) { }, } + vendor_snapshot_rlib { + name: "librust_vendor_available.rlib-std", + version: "30", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "librust_vendor_available.rlib-std.rlib", + }, + arm: { + src: "librust_vendor_available.rlib-std.rlib", + }, + }, + } + + vendor_snapshot_dylib { + name: "libstd", + version: "30", + target_arch: "arm64", + vendor: true, + sysroot: true, + arch: { + arm64: { + src: "libstd.dylib.so", + }, + arm: { + src: "libstd.dylib.so", + }, + }, + } + + vendor_snapshot_dylib { + name: "librust_vendor_available", + version: "30", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "librust_vendor_available.dylib.so", + }, + arm: { + src: "librust_vendor_available.dylib.so", + }, + }, + } + vendor_snapshot_object { name: "crtend_android", version: "30", @@ -921,6 +1026,9 @@ func TestVendorSnapshotUse(t *testing.T) { "vendor/liblog.so": nil, "vendor/libstd.rlib": nil, "vendor/librust_vendor_available.rlib": nil, + "vendor/librust_vendor_available.rlib-std.rlib": nil, + "vendor/libstd.dylib.so": nil, + "vendor/librust_vendor_available.dylib.so": nil, "vendor/crtbegin_so.o": nil, "vendor/crtend_so.o": nil, "vendor/libclang_rt.builtins-aarch64-android.a": nil, @@ -931,7 +1039,9 @@ func TestVendorSnapshotUse(t *testing.T) { } sharedVariant := "android_vendor.30_arm64_armv8-a_shared" - rlibVariant := "android_vendor.30_arm64_armv8-a_rlib_rlib-std" + rlibVariant := "android_vendor.30_arm64_armv8-a_rlib_dylib-std" + rlibRlibStdVariant := "android_vendor.30_arm64_armv8-a_rlib_rlib-std" + dylibVariant := "android_vendor.30_arm64_armv8-a_dylib" staticVariant := "android_vendor.30_arm64_armv8-a_static" binaryVariant := "android_vendor.30_arm64_armv8-a" @@ -963,14 +1073,9 @@ func TestVendorSnapshotUse(t *testing.T) { t.Errorf("wanted libclient AndroidMkStaticLibs %q, got %q", w, g) } - libclientAndroidMkRlibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkRlibs - if g, w := libclientAndroidMkRlibs, []string{"librust_vendor_available.vendor.rlib-std", "libstd.vendor"}; !reflect.DeepEqual(g, w) { - t.Errorf("wanted libclient libclientAndroidMkRlibs %q, got %q", w, g) - } - libclientAndroidMkDylibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkDylibs - if len(libclientAndroidMkDylibs) > 0 { - t.Errorf("wanted libclient libclientAndroidMkDylibs [], got %q", libclientAndroidMkDylibs) + if g, w := libclientAndroidMkDylibs, []string{"librust_vendor_available.vendor", "libstd.vendor"}; !reflect.DeepEqual(g, w) { + t.Errorf("wanted libclient libclientAndroidMkDylibs %q, got %q", w, libclientAndroidMkDylibs) } libclient32AndroidMkSharedLibs := ctx.ModuleForTests("libclient", shared32Variant).Module().(*Module).Properties.AndroidMkSharedLibs @@ -979,22 +1084,39 @@ func TestVendorSnapshotUse(t *testing.T) { } libclientRustAndroidMkRlibs := ctx.ModuleForTests("libclient_rust", rlibVariant).Module().(*Module).Properties.AndroidMkRlibs - if g, w := libclientRustAndroidMkRlibs, []string{"librust_vendor_available.vendor.rlib-std", "libstd.vendor"}; !reflect.DeepEqual(g, w) { - t.Errorf("wanted libclient libclientAndroidMkRlibs %q, got %q", w, g) + if g, w := libclientRustAndroidMkRlibs, []string{"librust_vendor_available.vendor"}; !reflect.DeepEqual(g, w) { + t.Errorf("wanted rlib libclient libclientAndroidMkRlibs %q, got %q", w, g) + } + + libclientRlibStdRustAndroidMkRlibs := ctx.ModuleForTests("libclient_rust", rlibRlibStdVariant).Module().(*Module).Properties.AndroidMkRlibs + if g, w := libclientRlibStdRustAndroidMkRlibs, []string{"librust_vendor_available.vendor.rlib-std", "libstd.vendor"}; !reflect.DeepEqual(g, w) { + t.Errorf("wanted rlib libclient libclientAndroidMkRlibs %q, got %q", w, g) + } + + libclientRustDylibAndroidMkDylibs := ctx.ModuleForTests("libclient_rust", dylibVariant).Module().(*Module).Properties.AndroidMkDylibs + if g, w := libclientRustDylibAndroidMkDylibs, []string{"librust_vendor_available.vendor", "libstd.vendor"}; !reflect.DeepEqual(g, w) { + t.Errorf("wanted dylib libclient libclientRustDylibAndroidMkDylibs %q, got %q", w, g) } // rust vendor snapshot must have ".vendor" suffix in AndroidMk librustVendorAvailableSnapshotModule := ctx.ModuleForTests("librust_vendor_available.vendor_rlib.30.arm64", rlibVariant).Module() librustVendorSnapshotMkName := android.AndroidMkEntriesForTest(t, ctx, librustVendorAvailableSnapshotModule)[0].EntryMap["LOCAL_MODULE"][0] - expectedRustVendorSnapshotName := "librust_vendor_available.vendor.rlib-std" + expectedRustVendorSnapshotName := "librust_vendor_available.vendor" if librustVendorSnapshotMkName != expectedRustVendorSnapshotName { t.Errorf("Unexpected rust vendor snapshot name in AndroidMk: %q, expected: %q\n", librustVendorSnapshotMkName, expectedRustVendorSnapshotName) } + librustVendorAvailableDylibSnapshotModule := ctx.ModuleForTests("librust_vendor_available.vendor_dylib.30.arm64", dylibVariant).Module() + librustVendorSnapshotDylibMkName := android.AndroidMkEntriesForTest(t, ctx, librustVendorAvailableDylibSnapshotModule)[0].EntryMap["LOCAL_MODULE"][0] + expectedRustVendorDylibSnapshotName := "librust_vendor_available.vendor" + if librustVendorSnapshotDylibMkName != expectedRustVendorDylibSnapshotName { + t.Errorf("Unexpected rust vendor snapshot name in AndroidMk: %q, expected: %q\n", librustVendorSnapshotDylibMkName, expectedRustVendorDylibSnapshotName) + } + rustVendorBinModule := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Module() - rustVendorBinMkRlibName := android.AndroidMkEntriesForTest(t, ctx, rustVendorBinModule)[0].EntryMap["LOCAL_RLIB_LIBRARIES"][0] - if rustVendorBinMkRlibName != expectedRustVendorSnapshotName { - t.Errorf("Unexpected rust rlib name in AndroidMk: %q, expected: %q\n", rustVendorBinMkRlibName, expectedRustVendorSnapshotName) + rustVendorBinMkDylibName := android.AndroidMkEntriesForTest(t, ctx, rustVendorBinModule)[0].EntryMap["LOCAL_DYLIB_LIBRARIES"][0] + if rustVendorBinMkDylibName != expectedRustVendorSnapshotName { + t.Errorf("Unexpected rust rlib name in AndroidMk: %q, expected: %q\n", rustVendorBinMkDylibName, expectedRustVendorSnapshotName) } binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustLink").Args["linkFlags"] @@ -1051,18 +1173,18 @@ func TestRecoverySnapshotCapture(t *testing.T) { crate_name: "recovery_available", } - rust_library_rlib { - name: "librecovery_rlib", + rust_library { + name: "librecovery_rustlib", recovery: true, srcs: ["foo.rs"], - crate_name: "recovery_rlib", + crate_name: "recovery_rustlib", } - rust_library_rlib { - name: "librecovery_available_rlib", + rust_library { + name: "librecovery_available_rustlib", recovery_available: true, srcs: ["foo.rs"], - crate_name: "recovery_available_rlib", + crate_name: "recovery_available_rustlib", } rust_binary { @@ -1113,13 +1235,29 @@ func TestRecoverySnapshotCapture(t *testing.T) { filepath.Join(staticDir, "librecovery_available.a.json")) // For rlib libraries, all recovery:true and recovery_available modules are captured. - rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant) + rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_dylib-std", archType, archVariant) rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") - cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant) - cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available_rlib", "librecovery_available_rlib.rlib", rlibDir, rlibVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.rlib", rlibDir, rlibVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available_rustlib", "librecovery_available_rustlib.rlib", rlibDir, rlibVariant) jsonFiles = append(jsonFiles, - filepath.Join(rlibDir, "librecovery_rlib.rlib.json"), - filepath.Join(rlibDir, "librecovery_available_rlib.rlib.json")) + filepath.Join(rlibDir, "librecovery_rustlib.rlib.json"), + filepath.Join(rlibDir, "librecovery_available_rustlib.rlib.json")) + + rlibRlibStdVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.rlib-std.rlib", rlibDir, rlibRlibStdVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available_rustlib", "librecovery_available_rustlib.rlib-std.rlib", rlibDir, rlibRlibStdVariant) + jsonFiles = append(jsonFiles, + filepath.Join(rlibDir, "librecovery_rustlib.rlib-std.rlib.json"), + filepath.Join(rlibDir, "librecovery_available_rustlib.rlib-std.rlib.json")) + + // For dylib libraries, all recovery:true and recovery_available modules are captured. + dylibVariant := fmt.Sprintf("android_recovery_%s_%s_dylib", archType, archVariant) + dylibDir := filepath.Join(snapshotVariantPath, archDir, "dylib") + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.dylib.so", dylibDir, dylibVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available_rustlib", "librecovery_available_rustlib.dylib.so", dylibDir, dylibVariant) + jsonFiles = append(jsonFiles, + filepath.Join(dylibDir, "librecovery_rustlib.dylib.so.json"), + filepath.Join(dylibDir, "librecovery_available_rustlib.dylib.so.json")) // For binary executables, all recovery:true and recovery_available modules are captured. if archType == "arm64" { @@ -1169,25 +1307,25 @@ func TestRecoverySnapshotExclude(t *testing.T) { exclude_from_recovery_snapshot: true, crate_name: "available_exclude", } - rust_library_rlib { - name: "libinclude_rlib", + rust_library { + name: "libinclude_rustlib", srcs: ["src/include.rs"], recovery_available: true, - crate_name: "include_rlib", + crate_name: "include_rustlib", } - rust_library_rlib { - name: "libexclude_rlib", + rust_library { + name: "libexclude_rustlib", srcs: ["src/exclude.rs"], recovery: true, exclude_from_recovery_snapshot: true, - crate_name: "exclude_rlib", + crate_name: "exclude_rustlib", } - rust_library_rlib { - name: "libavailable_exclude_rlib", + rust_library { + name: "libavailable_exclude_rustlib", srcs: ["src/exclude.rs"], recovery_available: true, exclude_from_recovery_snapshot: true, - crate_name: "available_exclude_rlib", + crate_name: "available_exclude_rustlib", } ` @@ -1198,11 +1336,11 @@ func TestRecoverySnapshotExclude(t *testing.T) { recovery: true, crate_name: "recovery", } - rust_library_rlib { - name: "librecovery_rlib", + rust_library { + name: "librecovery_rustlib", srcs: ["recovery.rs"], recovery: true, - crate_name: "recovery_rlib", + crate_name: "recovery_rustlib", } ` @@ -1220,14 +1358,25 @@ func TestRecoverySnapshotExclude(t *testing.T) { cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false, sharedRecoveryVariant) cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true, sharedRecoveryVariant) cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true, sharedRecoveryVariant) - cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude_rlib", false, rlibRecoveryVariant) - cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude_rlib", true, rlibRecoveryVariant) - cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude_rlib", true, rlibRecoveryVariant) + + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude_rustlib", false, rlibRecoveryVariant) + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude_rustlib", true, rlibRecoveryVariant) + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude_rustlib", true, rlibRlibStdRecoveryVariant) + + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude_rustlib", false, rlibRlibStdRecoveryVariant) + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude_rustlib", true, rlibRlibStdRecoveryVariant) + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude_rustlib", true, rlibRlibStdRecoveryVariant) + + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude_rustlib", false, dylibRecoveryVariant) + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude_rustlib", true, dylibRecoveryVariant) + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude_rustlib", true, dylibRecoveryVariant) // A recovery module is excluded, but by its path not the exclude_from_recovery_snapshot property // ('device/' and 'vendor/' are default excluded). See snapshot/recovery_snapshot.go for more detail. cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false, sharedRecoveryVariant) - cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery_rlib", false, rlibRecoveryVariant) + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery_rustlib", false, rlibRecoveryVariant) + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery_rustlib", false, rlibRlibStdRecoveryVariant) + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery_rustlib", false, dylibRecoveryVariant) // Verify the content of the recovery snapshot. @@ -1246,15 +1395,21 @@ func TestRecoverySnapshotExclude(t *testing.T) { archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant) - rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant) + rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_dylib-std", archType, archVariant) + rlibRlibStdVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant) + dylibVariant := fmt.Sprintf("android_recovery_%s_%s_dylib", archType, archVariant) sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") + dylibDir := filepath.Join(snapshotVariantPath, archDir, "dylib") // Included modules + cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json")) - cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude_rlib", "libinclude_rlib.rlib", rlibDir, rlibVariant) - includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "libinclude_rlib.rlib.json")) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude_rustlib", "libinclude_rustlib.rlib", rlibDir, rlibVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "libinclude_rustlib.rlib.json")) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude_rustlib", "libinclude_rustlib.rlib-std.rlib", rlibDir, rlibRlibStdVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "libinclude_rustlib.rlib-std.rlib.json")) // Excluded modules cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant) @@ -1263,12 +1418,27 @@ func TestRecoverySnapshotExclude(t *testing.T) { excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json")) cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant) excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json")) - cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude_rlib", "libexclude_rlib.rlib", rlibDir, rlibVariant) - excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libexclude_rlib.rlib.json")) - cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant) - excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librecovery_rlib.rlib.json")) - cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude_rlib", "libavailable_exclude_rlib.rlib", rlibDir, rlibVariant) - excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libavailable_exclude_rlib.rlib.json")) + + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude_rustlib", "libexclude_rustlib.rlib", rlibDir, rlibVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libexclude_rustlib.rlib.json")) + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.rlib", rlibDir, rlibVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librecovery_rustlib.rlib.json")) + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude_rustlib", "libavailable_exclude_rustlib.rlib", rlibDir, rlibVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libavailable_exclude_rustlib.rlib.json")) + + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude_rustlib", "libexclude_rustlib.rlib-std.rlib", rlibDir, rlibRlibStdVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libexclude_rustlib.rlib-std.rlib.json")) + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.rlib-std.rlib", rlibDir, rlibRlibStdVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librecovery_rustlib.rlib-std.rlib.json")) + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude_rustlib", "libavailable_exclude_rustlib.rlib-std.rlib", rlibDir, rlibRlibStdVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libavailable_exclude_rustlib.rlib-std.rlib.json")) + + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude_rustlib", "libexclude_rustlib.dylib.so", dylibDir, dylibVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libexclude_rustlib.dylib.so.json")) + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.dylib.so", dylibDir, dylibVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librecovery_rustlib.dylib.so.json")) + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude_rustlib", "libavailable_exclude_rustlib.dylib.so", dylibDir, dylibVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libavailable_exclude_rustlib.dylib.so.json")) } // Verify that each json file for an included module has a rule. @@ -1302,15 +1472,15 @@ func TestRecoverySnapshotDirected(t *testing.T) { srcs: ["foo.rs"], } - rust_library_rlib { - name: "librecovery_rlib", + rust_library { + name: "librecovery_rustlib", recovery: true, crate_name: "recovery", srcs: ["foo.rs"], } - rust_library_rlib { - name: "librecovery_available_rlib", + rust_library { + name: "librecovery_available_rustlib", recovery_available: true, crate_name: "recovery_available", srcs: ["foo.rs"], @@ -1335,7 +1505,7 @@ func TestRecoverySnapshotDirected(t *testing.T) { ctx := testRustRecoveryFsVersions(t, bp, rustMockedFiles, "current", "29", "current") ctx.Config().TestProductVariables.RecoverySnapshotModules = make(map[string]bool) ctx.Config().TestProductVariables.RecoverySnapshotModules["librecovery"] = true - ctx.Config().TestProductVariables.RecoverySnapshotModules["librecovery_rlib"] = true + ctx.Config().TestProductVariables.RecoverySnapshotModules["librecovery_rustlib"] = true ctx.Config().TestProductVariables.DirectedRecoverySnapshot = true // Check recovery snapshot output. @@ -1353,15 +1523,22 @@ func TestRecoverySnapshotDirected(t *testing.T) { archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant) - rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant) + rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_dylib-std", archType, archVariant) + rlibRlibStdVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant) + dylibVariant := fmt.Sprintf("android_recovery_%s_%s_dylib", archType, archVariant) sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") + dylibDir := filepath.Join(snapshotVariantPath, archDir, "dylib") // Included modules cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json")) - cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant) - includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_rlib.rlib.json")) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.rlib", rlibDir, rlibVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_rustlib.rlib.json")) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.rlib-std.rlib", rlibDir, rlibRlibStdVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_rustlib.rlib-std.rlib.json")) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.dylib.so", dylibDir, dylibVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(dylibDir, "librecovery_rustlib.dylib.so.json")) // TODO: When Rust supports the "prefer" property for prebuilts, perform this check. /* @@ -1374,8 +1551,12 @@ func TestRecoverySnapshotDirected(t *testing.T) { // are still included as fake modules. cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant) includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery_available.so.json")) - cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available_rlib", "librecovery_available_rlib.rlib", rlibDir, rlibVariant) - includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_available_rlib.rlib.json")) + cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available_rustlib", "librecovery_available_rustlib.rlib", rlibDir, rlibVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_available_rustlib.rlib.json")) + cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available_rustlib", "librecovery_available_rustlib.rlib-std.rlib", rlibDir, rlibRlibStdVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_available_rustlib.rlib-std.rlib.json")) + cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available_rustlib", "librecovery_available_rustlib.dylib.so", dylibDir, dylibVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(dylibDir, "librecovery_available_rustlib.dylib.so.json")) } // Verify that each json file for an included module has a rule. diff --git a/scripts/unpack-prebuilt-apex.sh b/scripts/unpack-prebuilt-apex.sh index 2a20e452a..18f4da236 100755 --- a/scripts/unpack-prebuilt-apex.sh +++ b/scripts/unpack-prebuilt-apex.sh @@ -17,7 +17,7 @@ set -eu # limitations under the License. # Tool to unpack an apex file and verify that the required files were extracted. -if [ $# -lt 7 ]; then +if [ $# -lt 6 ]; then echo "usage: $0 <deapaxer_path> <debugfs_path> <fsck.erofs_path> <apex file> <output_dir> <required_files>+" >&2 exit 1 fi diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go index d830968f6..ee1b5dbf6 100644 --- a/sdk/bootclasspath_fragment_sdk_test.go +++ b/sdk/bootclasspath_fragment_sdk_test.go @@ -86,27 +86,27 @@ func TestSnapshotWithBootclasspathFragment_ImageName(t *testing.T) { // Add a platform_bootclasspath that depends on the fragment. fixtureAddPlatformBootclasspathForBootclasspathFragmentWithExtra( - "com.android.art", "mybootclasspathfragment", java.ApexBootJarFragmentsForPlatformBootclasspath), + "com.android.art", "art-bootclasspath-fragment", java.ApexBootJarFragmentsForPlatformBootclasspath), java.PrepareForBootImageConfigTest, java.PrepareApexBootJarConfigsAndModules, android.FixtureWithRootAndroidBp(` sdk { name: "mysdk", - bootclasspath_fragments: ["mybootclasspathfragment"], + bootclasspath_fragments: ["art-bootclasspath-fragment"], } apex { name: "com.android.art", key: "com.android.art.key", bootclasspath_fragments: [ - "mybootclasspathfragment", + "art-bootclasspath-fragment", ], updatable: false, } bootclasspath_fragment { - name: "mybootclasspathfragment", + name: "art-bootclasspath-fragment", image_name: "art", contents: ["core1", "core2"], apex_available: ["com.android.art"], @@ -142,18 +142,18 @@ func TestSnapshotWithBootclasspathFragment_ImageName(t *testing.T) { ).RunTest(t) // A preparer to update the test fixture used when processing an unpackage snapshot. - preparerForSnapshot := fixtureAddPrebuiltApexForBootclasspathFragment("com.android.art", "mybootclasspathfragment") + preparerForSnapshot := fixtureAddPrebuiltApexForBootclasspathFragment("com.android.art", "art-bootclasspath-fragment") // Check that source on its own configures the bootImageConfig correctly. - java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/mybootclasspathfragment/android_common_apex10000/meta_lic") - java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic") + java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic") + java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic") CheckSnapshot(t, result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. prebuilt_bootclasspath_fragment { - name: "mybootclasspathfragment", + name: "art-bootclasspath-fragment", prefer: false, visibility: ["//visibility:public"], apex_available: ["com.android.art"], @@ -189,12 +189,12 @@ java_import { } `), checkAllCopyRules(` -.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv -.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv -.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv -.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv -.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv -.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv +.intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv +.intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv +.intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv +.intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv +.intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv +.intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv .intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/core1.jar .intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/core2.jar `), @@ -213,24 +213,24 @@ java_import { java.ApexBootJarDexJarPaths..., )..., ) - java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/snapshot/mybootclasspathfragment/android_common_com.android.art/meta_lic") - java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic") + java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic") + java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic") }), snapshotTestPreparer(checkSnapshotWithSourcePreferred, preparerForSnapshot), // Check the behavior of the snapshot when the source is preferred. snapshotTestChecker(checkSnapshotWithSourcePreferred, func(t *testing.T, result *android.TestResult) { - java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/mybootclasspathfragment/android_common_apex10000/meta_lic") - java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic") + java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic") + java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic") }), snapshotTestPreparer(checkSnapshotPreferredWithSource, preparerForSnapshot), // Check the behavior of the snapshot when it is preferred. snapshotTestChecker(checkSnapshotPreferredWithSource, func(t *testing.T, result *android.TestResult) { - java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/snapshot/prebuilt_mybootclasspathfragment/android_common_com.android.art/meta_lic") - java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic") + java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic") + java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic") }), ) 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 1b5443782..b2434712b 100644 --- a/starlark_import/unmarshal.go +++ b/starlark_import/unmarshal.go @@ -25,13 +25,18 @@ import ( ) func Unmarshal[T any](value starlark.Value) (T, error) { - var zero T - x, err := UnmarshalReflect(value, reflect.TypeOf(zero)) + x, err := UnmarshalReflect(value, reflect.TypeOf((*T)(nil)).Elem()) return x.Interface().(T), err } func UnmarshalReflect(value starlark.Value, ty reflect.Type) (reflect.Value, error) { + if ty == reflect.TypeOf((*starlark.Value)(nil)).Elem() { + return reflect.ValueOf(value), nil + } zero := reflect.Zero(ty) + if value == nil { + panic("nil value") + } var result reflect.Value if ty.Kind() == reflect.Interface { var err error @@ -286,3 +291,14 @@ func typeOfStarlarkValue(value starlark.Value) (reflect.Type, error) { return nil, fmt.Errorf("unimplemented starlark type: %s", value.Type()) } } + +// UnmarshalNoneable is like Unmarshal, but it will accept None as the top level (but not nested) +// starlark value. If the value is None, a nil pointer will be returned, otherwise a pointer +// to the result of Unmarshal will be returned. +func UnmarshalNoneable[T any](value starlark.Value) (*T, error) { + if _, ok := value.(starlark.NoneType); ok { + return nil, nil + } + ret, err := Unmarshal[T](value) + return &ret, err +} diff --git a/starlark_import/unmarshal_test.go b/starlark_import/unmarshal_test.go index ee7a9e340..bc0ea4c49 100644 --- a/starlark_import/unmarshal_test.go +++ b/starlark_import/unmarshal_test.go @@ -30,7 +30,7 @@ func createStarlarkValue(t *testing.T, code string) starlark.Value { return result["x"] } -func TestUnmarshallConcreteType(t *testing.T) { +func TestUnmarshalConcreteType(t *testing.T) { x, err := Unmarshal[string](createStarlarkValue(t, `"foo"`)) if err != nil { t.Error(err) @@ -41,7 +41,7 @@ func TestUnmarshallConcreteType(t *testing.T) { } } -func TestUnmarshallConcreteTypeWithInterfaces(t *testing.T) { +func TestUnmarshalConcreteTypeWithInterfaces(t *testing.T) { x, err := Unmarshal[map[string]map[string]interface{}](createStarlarkValue(t, `{"foo": {"foo2": "foo3"}, "bar": {"bar2": ["bar3"]}}`)) if err != nil { @@ -57,7 +57,22 @@ func TestUnmarshallConcreteTypeWithInterfaces(t *testing.T) { } } -func TestUnmarshall(t *testing.T) { +func TestUnmarshalToStarlarkValue(t *testing.T) { + x, err := Unmarshal[map[string]starlark.Value](createStarlarkValue(t, + `{"foo": "Hi", "bar": None}`)) + if err != nil { + t.Error(err) + return + } + if x["foo"].(starlark.String).GoString() != "Hi" { + t.Errorf("Expected \"Hi\", got: %q", x["foo"].(starlark.String).GoString()) + } + if x["bar"].Type() != "NoneType" { + t.Errorf("Expected \"NoneType\", got: %q", x["bar"].Type()) + } +} + +func TestUnmarshal(t *testing.T) { testCases := []struct { input string expected interface{} diff --git a/tests/genrule_sandbox_test.py b/tests/genrule_sandbox_test.py index a9f0c9b50..0cebc2aa0 100755 --- a/tests/genrule_sandbox_test.py +++ b/tests/genrule_sandbox_test.py @@ -17,34 +17,37 @@ import argparse import collections import json -import os.path +import os import subprocess +import sys import tempfile -SRC_ROOT_DIR = os.path.abspath(__file__ + "/../../../..") +def get_top() -> str: + path = '.' + while not os.path.isfile(os.path.join(path, 'build/soong/tests/genrule_sandbox_test.py')): + if os.path.abspath(path) == '/': + sys.exit('Could not find android source tree root.') + path = os.path.join(path, '..') + return os.path.abspath(path) - -def _module_graph_path(out_dir): - return os.path.join(SRC_ROOT_DIR, out_dir, "soong", "module-actions.json") - - -def _build_with_soong(targets, target_product, out_dir, extra_env={}): +def _build_with_soong(targets, target_product, *, keep_going = False, extra_env={}): env = { + **os.environ, "TARGET_PRODUCT": target_product, "TARGET_BUILD_VARIANT": "userdebug", } - env.update(os.environ) env.update(extra_env) args = [ "build/soong/soong_ui.bash", "--make-mode", "--skip-soong-tests", ] + if keep_going: + args.append("-k") args.extend(targets) try: - out = subprocess.check_output( + subprocess.check_output( args, - cwd=SRC_ROOT_DIR, env=env, ) except subprocess.CalledProcessError as e: @@ -55,14 +58,13 @@ def _build_with_soong(targets, target_product, out_dir, extra_env={}): def _find_outputs_for_modules(modules, out_dir, target_product): - module_path = os.path.join( - SRC_ROOT_DIR, out_dir, "soong", "module-actions.json" - ) + module_path = os.path.join(out_dir, "soong", "module-actions.json") if not os.path.exists(module_path): - _build_with_soong(["json-module-graph"], target_product, out_dir) + _build_with_soong(["json-module-graph"], target_product) - action_graph = json.load(open(_module_graph_path(out_dir))) + with open(module_path) as f: + action_graph = json.load(f) module_to_outs = collections.defaultdict(set) for mod in action_graph: @@ -74,50 +76,15 @@ def _find_outputs_for_modules(modules, out_dir, target_product): return module_to_outs -def _store_outputs_to_tmp(output_files): - try: - tempdir = tempfile.TemporaryDirectory() - for f in output_files: - out = subprocess.check_output( - ["cp", "--parents", f, tempdir.name], - cwd=SRC_ROOT_DIR, - ) - return tempdir - except subprocess.CalledProcessError as e: - print(e) - print(e.stdout) - print(e.stderr) - - -def _diff_outs(file1, file2, show_diff): - output = None - base_args = ["diff"] - if not show_diff: - base_args.append("--brief") - try: - args = base_args + [file1, file2] - output = subprocess.check_output( - args, - cwd=SRC_ROOT_DIR, - ) - except subprocess.CalledProcessError as e: - if e.returncode == 1: - if show_diff: - return output - return True - return None - - -def _compare_outputs(module_to_outs, tempdir, show_diff): +def _compare_outputs(module_to_outs, tempdir) -> dict[str, list[str]]: different_modules = collections.defaultdict(list) for module, outs in module_to_outs.items(): for out in outs: - output = None - diff = _diff_outs(os.path.join(tempdir.name, out), out, show_diff) - if diff: - different_modules[module].append(diff) + try: + subprocess.check_output(["diff", os.path.join(tempdir, out), out]) + except subprocess.CalledProcessError as e: + different_modules[module].append(e.stdout) - tempdir.cleanup() return different_modules @@ -138,53 +105,56 @@ def main(): "--show-diff", "-d", action="store_true", - required=False, help="whether to display differing files", ) parser.add_argument( "--output-paths-only", "-o", action="store_true", - required=False, help="Whether to only return the output paths per module", ) args = parser.parse_args() + os.chdir(get_top()) out_dir = os.environ.get("OUT_DIR", "out") - target_product = args.target_product - modules = set(args.modules) - module_to_outs = _find_outputs_for_modules(modules, out_dir, target_product) + print("finding output files for the modules...") + module_to_outs = _find_outputs_for_modules(set(args.modules), out_dir, args.target_product) if not module_to_outs: - print("No outputs found") - exit(1) + sys.exit("No outputs found") if args.output_paths_only: for m, o in module_to_outs.items(): print(f"{m} outputs: {o}") - exit(0) - - all_outs = set() - for outs in module_to_outs.values(): - all_outs.update(outs) - print("build without sandboxing") - _build_with_soong(list(all_outs), target_product, out_dir) - tempdir = _store_outputs_to_tmp(all_outs) - print("build with sandboxing") - _build_with_soong( - list(all_outs), - target_product, - out_dir, - extra_env={"GENRULE_SANDBOXING": "true"}, - ) - diffs = _compare_outputs(module_to_outs, tempdir, args.show_diff) - if len(diffs) == 0: - print("All modules are correct") - elif args.show_diff: - for m, d in diffs.items(): - print(f"Module {m} has diffs {d}") - else: - print(f"Modules {list(diffs.keys())} have diffs") + sys.exit(0) + + all_outs = list(set.union(*module_to_outs.values())) + + print("building without sandboxing...") + _build_with_soong(all_outs, args.target_product) + with tempfile.TemporaryDirectory() as tempdir: + for f in all_outs: + subprocess.check_call(["cp", "--parents", f, tempdir]) + + print("building with sandboxing...") + _build_with_soong( + all_outs, + args.target_product, + # We've verified these build without sandboxing already, so do the sandboxing build + # with keep_going = True so that we can find all the genrules that fail to build with + # sandboxing. + keep_going = True, + extra_env={"GENRULE_SANDBOXING": "true"}, + ) + + diffs = _compare_outputs(module_to_outs, tempdir) + if len(diffs) == 0: + print("All modules are correct") + elif args.show_diff: + for m, d in diffs.items(): + print(f"Module {m} has diffs {d}") + else: + print(f"Modules {list(diffs.keys())} have diffs") if __name__ == "__main__": diff --git a/tests/lib.sh b/tests/lib.sh index 4aaf272a7..40b317b06 100644 --- a/tests/lib.sh +++ b/tests/lib.sh @@ -147,6 +147,7 @@ function create_mock_bazel { symlink_directory external/bazelbuild-rules_go symlink_directory external/bazelbuild-rules_license symlink_directory external/bazelbuild-kotlin-rules + symlink_directory external/bazelbuild-rules_java symlink_file WORKSPACE symlink_file BUILD diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh index 43a9f0fed..48f654e1c 100755 --- a/tests/run_integration_tests.sh +++ b/tests/run_integration_tests.sh @@ -10,7 +10,7 @@ TOP="$(readlink -f "$(dirname "$0")"/../../..)" "$TOP/build/soong/tests/persistent_bazel_test.sh" "$TOP/build/soong/tests/soong_test.sh" "$TOP/build/soong/tests/stale_metrics_files_test.sh" -"$TOP/build/bazel/ci/rbc_regression_test.sh" aosp_arm64-userdebug +"$TOP/prebuilts/build-tools/linux-x86/bin/py3-cmd" "$TOP/build/bazel/ci/rbc_dashboard.py" aosp_arm64-userdebug # The following tests build against the full source tree and don't rely on the # mock client. diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh index 19987f204..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,12 +111,22 @@ 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 \ -I /system/lib64/android.hardware.security.rkp-V3-ndk.so \ -I /system/lib64/android.hardware.security.sharedsecret-V1-ndk.so \ -I /system/lib64/android.security.compat-ndk.so \ + -I /system/lib64/libcuttlefish_allocd_utils.so \ + -I /system/lib64/libcuttlefish_device_config_proto.so \ + -I /system/lib64/libcuttlefish_device_config.so \ + -I /system/lib64/libcuttlefish_fs.so \ + -I /system/lib64/libcuttlefish_kernel_log_monitor_utils.so \ + -I /system/lib64/libcuttlefish_utils.so \ + -I /system/lib64/libfruit.so \ + -I /system/lib64/libgflags.so \ -I /system/lib64/libkeymaster4_1support.so \ -I /system/lib64/libkeymaster4support.so \ -I /system/lib64/libkeymint.so \ @@ -126,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. @@ -223,4 +242,65 @@ function test_sbom_aosp_cf_x86_64_phone { cleanup "${out_dir}" } -test_sbom_aosp_cf_x86_64_phone
\ No newline at end of file +function test_sbom_unbundled_apex { + # Setup + out_dir="$(setup)" + + # run_soong to build com.android.adbd.apex + run_soong "module_arm64" "${out_dir}" "sbom deapexer" "com.android.adbd" + + deapexer=${out_dir}/host/linux-x86/bin/deapexer + debugfs=${out_dir}/host/linux-x86/bin/debugfs_static + apex_file=${out_dir}/target/product/module_arm64/system/apex/com.android.adbd.apex + echo "============ Diffing files in $apex_file and SBOM" + set +e + # deapexer prints the list of all files and directories + # sed extracts the file/directory names + # grep removes directories + # sed removes leading ./ in file names + diff -I /system/apex/com.android.adbd.apex -I apex_manifest.pb \ + <($deapexer --debugfs_path=$debugfs list --extents ${apex_file} | sed -E 's#(.*) \[.*\]$#\1#' | grep -v "/$" | sed -E 's#^\./(.*)#\1#' | sort -n) \ + <(grep '"fileName": ' ${apex_file}.spdx.json | sed -E 's/.*"fileName": "(.*)",/\1/' | sort -n ) + + if [ $? != "0" ]; then + echo "Diffs found in $apex_file and SBOM" + exit 1 + else + echo "No diffs." + fi + set -e + + # Teardown + cleanup "${out_dir}" +} + +function test_sbom_unbundled_apk { + # Setup + out_dir="$(setup)" + + # run_soong to build Browser2.apk + run_soong "module_arm64" "${out_dir}" "sbom" "Browser2" + + sbom_file=${out_dir}/target/product/module_arm64/system/product/app/Browser2/Browser2.apk.spdx.json + echo "============ Diffing files in Browser2.apk and SBOM" + set +e + # There is only one file in SBOM of APKs + diff \ + <(echo "/system/product/app/Browser2/Browser2.apk" ) \ + <(grep '"fileName": ' ${sbom_file} | sed -E 's/.*"fileName": "(.*)",/\1/' ) + + if [ $? != "0" ]; then + echo "Diffs found in $sbom_file" + exit 1 + else + echo "No diffs." + fi + set -e + + # Teardown + cleanup "${out_dir}" +} + +test_sbom_aosp_cf_x86_64_phone +test_sbom_unbundled_apex +test_sbom_unbundled_apk
\ No newline at end of file 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" { diff --git a/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto b/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto index 4aee88b68..5b4400225 100644 --- a/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto +++ b/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto @@ -38,6 +38,9 @@ message Bp2buildConversionProgress { // Total number of transitive dependencies. int32 num_deps = 5; + + // Unconverted reasons from heuristics + repeated string unconverted_reasons_from_heuristics = 6; } // Modules that the transitive dependencies were identified for. diff --git a/zip/cmd/BUILD.bazel b/zip/cmd/BUILD.bazel deleted file mode 100644 index e04a1e10d..000000000 --- a/zip/cmd/BUILD.bazel +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (C) 2022 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# TODO(b/194644518): Switch to the source version when Bazel can build go -# binaries. -alias( - name = "soong_zip", - actual = "//prebuilts/build-tools:linux-x86/bin/soong_zip", -) diff --git a/zip/cmd/main.go b/zip/cmd/main.go index a2ccc2011..5231faec9 100644 --- a/zip/cmd/main.go +++ b/zip/cmd/main.go @@ -173,6 +173,7 @@ func main() { cpuProfile := flags.String("cpuprofile", "", "write cpu profile to file") traceFile := flags.String("trace", "", "write trace to file") sha256Checksum := flags.Bool("sha256", false, "add a zip header to each file containing its SHA256 digest") + doNotWrite := flags.Bool("n", false, "Nothing is written to disk -- all other work happens") flags.Var(&rootPrefix{}, "P", "path prefix within the zip at which to place files") flags.Var(&listFiles{}, "l", "file containing list of files to zip") @@ -236,6 +237,7 @@ func main() { StoreSymlinks: *symlinks, IgnoreMissingFiles: *ignoreMissingFiles, Sha256Checksum: *sha256Checksum, + DoNotWrite: *doNotWrite, }) if err != nil { fmt.Fprintln(os.Stderr, "error:", err.Error()) diff --git a/zip/zip.go b/zip/zip.go index 5e1a10462..30a2ee762 100644 --- a/zip/zip.go +++ b/zip/zip.go @@ -282,6 +282,7 @@ type ZipArgs struct { StoreSymlinks bool IgnoreMissingFiles bool Sha256Checksum bool + DoNotWrite bool Stderr io.Writer Filesystem pathtools.FileSystem @@ -400,7 +401,9 @@ func Zip(args ZipArgs) error { var zipErr error - if !args.WriteIfChanged { + if args.DoNotWrite { + out = io.Discard + } else if !args.WriteIfChanged { f, err := os.Create(args.OutputFilePath) if err != nil { return err @@ -421,7 +424,7 @@ func Zip(args ZipArgs) error { return zipErr } - if args.WriteIfChanged { + if args.WriteIfChanged && !args.DoNotWrite { err := pathtools.WriteFileIfChanged(args.OutputFilePath, buf.Bytes(), 0666) if err != nil { return err |