diff options
208 files changed, 9325 insertions, 2610 deletions
diff --git a/aconfig/Android.bp b/aconfig/Android.bp index ae8276f39..d2ddfdfc6 100644 --- a/aconfig/Android.bp +++ b/aconfig/Android.bp @@ -14,20 +14,24 @@ bootstrap_go_package { "soong-bazel", "soong-android", "soong-java", + "soong-rust", ], srcs: [ "aconfig_declarations.go", "aconfig_values.go", "aconfig_value_set.go", "all_aconfig_declarations.go", + "cc_aconfig_library.go", "init.go", "java_aconfig_library.go", "testing.go", + "rust_aconfig_library.go", ], testSrcs: [ "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..4e199dd24 100644 --- a/aconfig/aconfig_declarations.go +++ b/aconfig/aconfig_declarations.go @@ -17,8 +17,9 @@ package aconfig import ( "android/soong/android" "fmt" - "github.com/google/blueprint" "strings" + + "github.com/google/blueprint" ) type DeclarationsModule struct { @@ -96,6 +97,15 @@ func joinAndPrefix(prefix string, values []string) string { return sb.String() } +func optionalVariable(prefix string, value string) string { + var sb strings.Builder + if value != "" { + sb.WriteString(prefix) + sb.WriteString(value) + } + return sb.String() +} + // Provider published by aconfig_value_set type declarationsProviderData struct { Package string @@ -123,15 +133,17 @@ func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.Module // Intermediate format inputFiles := android.PathsForModuleSrc(ctx, module.properties.Srcs) intermediatePath := android.PathForModuleOut(ctx, "intermediate.pb") + defaultPermission := ctx.Config().ReleaseAconfigFlagDefaultPermission() 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, - "values": joinAndPrefix(" --values ", module.properties.Values), + "release_version": ctx.Config().ReleaseVersion(), + "package": module.properties.Package, + "declarations": android.JoinPathsWithPrefix(inputFiles, "--declarations "), + "values": joinAndPrefix(" --values ", module.properties.Values), + "default-permission": optionalVariable(" --default-permission ", defaultPermission), }, }) 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..797388d6c 100644 --- a/aconfig/init.go +++ b/aconfig/init.go @@ -16,6 +16,7 @@ package aconfig import ( "android/soong/android" + "github.com/google/blueprint" ) @@ -27,23 +28,25 @@ var ( blueprint.RuleParams{ Command: `${aconfig} create-cache` + ` --package ${package}` + - ` --declarations ${in}` + + ` ${declarations}` + ` ${values}` + + ` ${default-permission}` + ` --cache ${out}.tmp` + - ` && ( if cmp -s ${out}.tmp ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`, + ` && ( if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`, // ` --build-id ${release_version}` + CommandDeps: []string{ "${aconfig}", }, Restat: true, - }, "release_version", "package", "values") + }, "release_version", "package", "declarations", "values", "default-permission") // For java_aconfig_library: Generate java file - srcJarRule = pctx.AndroidStaticRule("aconfig_srcjar", + javaRule = pctx.AndroidStaticRule("java_aconfig_library", blueprint.RuleParams{ Command: `rm -rf ${out}.tmp` + ` && mkdir -p ${out}.tmp` + ` && ${aconfig} create-java-lib` + + ` --mode ${mode}` + ` --cache ${in}` + ` --out ${out}.tmp` + ` && $soong_zip -write_if_changed -jar -o ${out} -C ${out}.tmp -D ${out}.tmp` + @@ -53,7 +56,35 @@ var ( "$soong_zip", }, Restat: true, - }) + }, "mode") + + // For java_aconfig_library: Generate java file + cppRule = pctx.AndroidStaticRule("cc_aconfig_library", + blueprint.RuleParams{ + Command: `rm -rf ${gendir}` + + ` && mkdir -p ${gendir}` + + ` && ${aconfig} create-cpp-lib` + + ` --cache ${in}` + + ` --out ${gendir}`, + CommandDeps: []string{ + "$aconfig", + "$soong_zip", + }, + }, "gendir") + + rustRule = pctx.AndroidStaticRule("rust_aconfig_library", + blueprint.RuleParams{ + Command: `rm -rf ${gendir}` + + ` && mkdir -p ${gendir}` + + ` && ${aconfig} create-rust-lib` + + ` --mode ${mode}` + + ` --cache ${in}` + + ` --out ${gendir}`, + CommandDeps: []string{ + "$aconfig", + "$soong_zip", + }, + }, "gendir", "mode") // For all_aconfig_declarations allDeclarationsRule = pctx.AndroidStaticRule("all_aconfig_declarations_dump", @@ -75,6 +106,8 @@ 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.RegisterModuleType("rust_aconfig_library", RustAconfigLibraryFactory) ctx.RegisterParallelSingletonType("all_aconfig_declarations", AllAconfigDeclarationsFactory) } diff --git a/aconfig/java_aconfig_library.go b/aconfig/java_aconfig_library.go index 0eeb14ffc..53f8bd1ba 100644 --- a/aconfig/java_aconfig_library.go +++ b/aconfig/java_aconfig_library.go @@ -30,6 +30,9 @@ var declarationsTag = declarationsTagType{} type JavaAconfigDeclarationsLibraryProperties struct { // name of the aconfig_declarations module to generate a library for Aconfig_declarations string + + // whether to generate test mode version of the library + Test bool } type JavaAconfigDeclarationsLibraryCallbacks struct { @@ -51,7 +54,7 @@ func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) DepsMutator(module *ja } } -func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuildActions(ctx android.ModuleContext) android.Path { +func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuildActions(module *java.GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path { // Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag declarationsModules := ctx.GetDirectDepsWithTag(declarationsTag) if len(declarationsModules) != 1 { @@ -59,13 +62,27 @@ func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuild } declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData) + // Generate the action to build the srcjar srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar") + var mode string + if callbacks.properties.Test { + mode = "test" + } else { + mode = "production" + } ctx.Build(pctx, android.BuildParams{ - Rule: srcJarRule, + Rule: javaRule, Input: declarations.IntermediatePath, Output: srcJarPath, Description: "aconfig.srcjar", + Args: map[string]string{ + "mode": mode, + }, }) + // Tell the java module about the .aconfig files, so they can be propagated up the dependency chain. + // TODO: It would be nice to have that propagation code here instead of on java.Module and java.JavaInfo. + module.AddAconfigIntermediate(declarations.IntermediatePath) + return srcJarPath } diff --git a/aconfig/java_aconfig_library_test.go b/aconfig/java_aconfig_library_test.go new file mode 100644 index 000000000..af50848f1 --- /dev/null +++ b/aconfig/java_aconfig_library_test.go @@ -0,0 +1,191 @@ +// Copyright 2023 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aconfig + +import ( + "fmt" + "strings" + "testing" + + "android/soong/android" + "android/soong/java" +) + +// Note: These tests cover the code in the java package. It'd be ideal of that code could +// be in the aconfig package. + +// With the bp parameter that defines a my_module, make sure it has the LOCAL_ACONFIG_FILES entries +func runJavaAndroidMkTest(t *testing.T, bp string) { + result := android.GroupFixturePreparers( + PrepareForTestWithAconfigBuildComponents, + java.PrepareForTestWithJavaDefaultModules). + ExtendWithErrorHandler(android.FixtureExpectsNoErrors). + RunTestWithBp(t, bp+` + aconfig_declarations { + name: "my_aconfig_declarations", + package: "com.example.package", + srcs: ["foo.aconfig"], + } + + java_aconfig_library { + name: "my_java_aconfig_library", + aconfig_declarations: "my_aconfig_declarations", + } + `) + + module := result.ModuleForTests("my_module", "android_common").Module() + + entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0] + + makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"] + android.AssertIntEquals(t, "len(LOCAL_ACONFIG_FILES)", 1, len(makeVar)) + if !strings.HasSuffix(makeVar[0], "intermediate.pb") { + t.Errorf("LOCAL_ACONFIG_FILES should end with /intermediates.pb, instead it is: %s", makeVar[0]) + } +} + +func TestAndroidMkJavaLibrary(t *testing.T) { + bp := ` + java_library { + name: "my_module", + srcs: [ + "src/foo.java", + ], + static_libs: [ + "my_java_aconfig_library", + ], + platform_apis: true, + } + ` + + runJavaAndroidMkTest(t, bp) +} + +func TestAndroidMkAndroidApp(t *testing.T) { + bp := ` + android_app { + name: "my_module", + srcs: [ + "src/foo.java", + ], + static_libs: [ + "my_java_aconfig_library", + ], + platform_apis: true, + } + ` + + runJavaAndroidMkTest(t, bp) +} + +func TestAndroidMkBinary(t *testing.T) { + bp := ` + java_binary { + name: "my_module", + srcs: [ + "src/foo.java", + ], + static_libs: [ + "my_java_aconfig_library", + ], + platform_apis: true, + main_class: "foo", + } + ` + + runJavaAndroidMkTest(t, bp) +} + +func TestAndroidMkAndroidLibrary(t *testing.T) { + bp := ` + android_library { + name: "my_module", + srcs: [ + "src/foo.java", + ], + static_libs: [ + "my_java_aconfig_library", + ], + platform_apis: true, + } + ` + + runJavaAndroidMkTest(t, bp) +} + +func TestAndroidMkBinaryThatLinksAgainstAar(t *testing.T) { + // Tests AndroidLibrary's propagation of flags through JavaInfo + bp := ` + android_library { + name: "some_library", + srcs: [ + "src/foo.java", + ], + static_libs: [ + "my_java_aconfig_library", + ], + platform_apis: true, + } + java_binary { + name: "my_module", + srcs: [ + "src/bar.java", + ], + static_libs: [ + "some_library", + ], + platform_apis: true, + main_class: "foo", + } + ` + + runJavaAndroidMkTest(t, bp) +} + +func testCodegenMode(t *testing.T, bpMode string, ruleMode string) { + result := android.GroupFixturePreparers( + PrepareForTestWithAconfigBuildComponents, + java.PrepareForTestWithJavaDefaultModules). + ExtendWithErrorHandler(android.FixtureExpectsNoErrors). + RunTestWithBp(t, fmt.Sprintf(` + aconfig_declarations { + name: "my_aconfig_declarations", + package: "com.example.package", + srcs: ["foo.aconfig"], + } + + java_aconfig_library { + name: "my_java_aconfig_library", + aconfig_declarations: "my_aconfig_declarations", + %s + } + `, bpMode)) + + module := result.ModuleForTests("my_java_aconfig_library", "android_common") + rule := module.Rule("java_aconfig_library") + android.AssertStringEquals(t, "rule must contain test mode", rule.Args["mode"], ruleMode) +} + +func TestDefaultProdMode(t *testing.T) { + testCodegenMode(t, "", "production") +} + +func TestProdMode(t *testing.T) { + testCodegenMode(t, "test: false,", "production") +} + +func TestTestMode(t *testing.T) { + testCodegenMode(t, "test: true,", "test") +} diff --git a/aconfig/rust_aconfig_library.go b/aconfig/rust_aconfig_library.go new file mode 100644 index 000000000..de41776a3 --- /dev/null +++ b/aconfig/rust_aconfig_library.go @@ -0,0 +1,89 @@ +package aconfig + +import ( + "android/soong/android" + "android/soong/rust" + "fmt" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" +) + +type rustDeclarationsTagType struct { + blueprint.BaseDependencyTag +} + +var rustDeclarationsTag = rustDeclarationsTagType{} + +type RustAconfigLibraryProperties struct { + // name of the aconfig_declarations module to generate a library for + Aconfig_declarations string + Test *bool +} + +type aconfigDecorator struct { + *rust.BaseSourceProvider + + Properties RustAconfigLibraryProperties +} + +func NewRustAconfigLibrary(hod android.HostOrDeviceSupported) (*rust.Module, *aconfigDecorator) { + aconfig := &aconfigDecorator{ + BaseSourceProvider: rust.NewSourceProvider(), + Properties: RustAconfigLibraryProperties{}, + } + + module := rust.NewSourceProviderModule(android.HostAndDeviceSupported, aconfig, false, false) + return module, aconfig +} + +// rust_aconfig_library generates aconfig rust code from the provided aconfig declaration. This module type will +// create library variants that can be used as a crate dependency by adding it to the rlibs, dylibs, and rustlibs +// properties of other modules. +func RustAconfigLibraryFactory() android.Module { + module, _ := NewRustAconfigLibrary(android.HostAndDeviceSupported) + return module.Init() +} + +func (a *aconfigDecorator) SourceProviderProps() []interface{} { + return append(a.BaseSourceProvider.SourceProviderProps(), &a.Properties) +} + +func (a *aconfigDecorator) GenerateSource(ctx rust.ModuleContext, deps rust.PathDeps) android.Path { + generatedDir := android.PathForModuleGen(ctx) + generatedSource := android.PathForModuleGen(ctx, "src", "lib.rs") + + declarationsModules := ctx.GetDirectDepsWithTag(rustDeclarationsTag) + + if len(declarationsModules) != 1 { + panic(fmt.Errorf("Exactly one aconfig_declarations property required")) + } + declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData) + + mode := "production" + if proptools.Bool(a.Properties.Test) { + mode = "test" + } + + ctx.Build(pctx, android.BuildParams{ + Rule: rustRule, + Input: declarations.IntermediatePath, + Outputs: []android.WritablePath{ + generatedSource, + }, + Description: "rust_aconfig_library", + Args: map[string]string{ + "gendir": generatedDir.String(), + "mode": mode, + }, + }) + a.BaseSourceProvider.OutputFiles = android.Paths{generatedSource} + return generatedSource +} + +func (a *aconfigDecorator) SourceProviderDeps(ctx rust.DepsContext, deps rust.Deps) rust.Deps { + deps = a.BaseSourceProvider.SourceProviderDeps(ctx, deps) + deps.Rustlibs = append(deps.Rustlibs, "libflags_rust") + ctx.AddDependency(ctx.Module(), rustDeclarationsTag, a.Properties.Aconfig_declarations) + return deps +} diff --git a/aconfig/rust_aconfig_library_test.go b/aconfig/rust_aconfig_library_test.go new file mode 100644 index 000000000..17385c3d1 --- /dev/null +++ b/aconfig/rust_aconfig_library_test.go @@ -0,0 +1,60 @@ +package aconfig + +import ( + "android/soong/android" + "android/soong/rust" + "fmt" + "testing" +) + +func TestRustAconfigLibrary(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForTestWithAconfigBuildComponents, + rust.PrepareForTestWithRustIncludeVndk, + android.PrepareForTestWithArchMutator, + android.PrepareForTestWithDefaults, + android.PrepareForTestWithPrebuilts, + ). + ExtendWithErrorHandler(android.FixtureExpectsNoErrors). + RunTestWithBp(t, fmt.Sprintf(` + rust_library { + name: "libflags_rust", // test mock + crate_name: "flags_rust", + srcs: ["lib.rs"], + } + aconfig_declarations { + name: "my_aconfig_declarations", + package: "com.example.package", + srcs: ["foo.aconfig"], + } + + rust_aconfig_library { + name: "libmy_rust_aconfig_library", + crate_name: "my_rust_aconfig_library", + aconfig_declarations: "my_aconfig_declarations", + } + `)) + + sourceVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_source") + rule := sourceVariant.Rule("rust_aconfig_library") + android.AssertStringEquals(t, "rule must contain production mode", rule.Args["mode"], "production") + + dylibVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_dylib") + rlibRlibStdVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_rlib_rlib-std") + rlibDylibStdVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_rlib_dylib-std") + + variants := []android.TestingModule{ + dylibVariant, + rlibDylibStdVariant, + rlibRlibStdVariant, + } + + for _, variant := range variants { + android.AssertStringEquals( + t, + "dylib variant builds from generated rust code", + "out/soong/.intermediates/libmy_rust_aconfig_library/android_arm64_armv8-a_source/gen/src/lib.rs", + variant.Rule("rustc").Inputs[0].RelativeToTop().String(), + ) + } +} 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..056c1a87a 100644 --- a/android/allowlists/allowlists.go +++ b/android/allowlists/allowlists.go @@ -121,6 +121,7 @@ var ( "development/sdk": Bp2BuildDefaultTrueRecursively, "external/aac": Bp2BuildDefaultTrueRecursively, + "external/abseil-cpp": Bp2BuildDefaultTrueRecursively, "external/arm-optimized-routines": Bp2BuildDefaultTrueRecursively, "external/auto": Bp2BuildDefaultTrue, "external/auto/android-annotation-stubs": Bp2BuildDefaultTrueRecursively, @@ -141,11 +142,13 @@ 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/gflags": Bp2BuildDefaultTrueRecursively, "external/google-benchmark": Bp2BuildDefaultTrueRecursively, "external/googletest": Bp2BuildDefaultTrueRecursively, + "external/guava": Bp2BuildDefaultTrueRecursively, "external/gwp_asan": Bp2BuildDefaultTrueRecursively, "external/hamcrest": Bp2BuildDefaultTrueRecursively, "external/icu": Bp2BuildDefaultTrueRecursively, @@ -188,7 +191,11 @@ var ( "external/ow2-asm": Bp2BuildDefaultTrueRecursively, "external/pcre": Bp2BuildDefaultTrueRecursively, "external/protobuf": Bp2BuildDefaultTrueRecursively, + "external/python/pyyaml/lib/yaml": Bp2BuildDefaultTrueRecursively, "external/python/six": Bp2BuildDefaultTrueRecursively, + "external/python/jinja/src": Bp2BuildDefaultTrueRecursively, + "external/python/markupsafe/src": Bp2BuildDefaultTrueRecursively, + "external/python/setuptools": Bp2BuildDefaultTrueRecursively, "external/rappor": Bp2BuildDefaultTrueRecursively, "external/scudo": Bp2BuildDefaultTrueRecursively, "external/selinux/checkpolicy": Bp2BuildDefaultTrueRecursively, @@ -227,6 +234,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,8 +437,11 @@ 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-rules_python":/* recursive = */ true, + "external/bazelbuild-rules_rust":/* recursive = */ true, "external/bazelbuild-kotlin-rules":/* recursive = */ true, "external/bazel-skylib":/* recursive = */ true, "external/protobuf":/* recursive = */ false, @@ -458,6 +469,7 @@ var ( "prebuilts/sdk/tools":/* recursive = */ false, "prebuilts/r8":/* recursive = */ false, "prebuilts/runtime":/* recursive = */ false, + "prebuilts/rust":/* recursive = */ true, // not recursive due to conflicting workspace paths in tools/atest/bazel/rules "tools/asuite/atest":/* recursive = */ false, @@ -471,8 +483,36 @@ var ( } Bp2buildModuleAlwaysConvertList = []string{ + // ext + "tagsoup", + + // framework-res + "remote-color-resources-compile-public", + "remote-color-resources-compile-colors", + + // framework-minus-apex + "android.mime.types.minimized", + "debian.mime.types.minimized", + "framework-javastream-protos", + "libview-inspector-annotation-processor", + + // services + "apache-commons-math", + "cbor-java", + "icu4j_calendar_astronomer", + "json", + "remote-color-resources-compile-public", + "statslog-art-java-gen", + "statslog-framework-java-gen", + + "AndroidCommonLint", + "ImmutabilityAnnotation", + "ImmutabilityAnnotationProcessorHostLibrary", + "libidmap2_policies", "libSurfaceFlingerProp", + "toolbox_input_labels", + // cc mainline modules // com.android.media.swcodec @@ -490,7 +530,6 @@ var ( "code_coverage.policy.other", "codec2_soft_exports", "compatibility_matrix_schema", - "flatbuffer_headers", "framework-connectivity-protos", "gemmlowp_headers", "gl_headers", @@ -613,10 +652,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 +709,7 @@ var ( "libcodec2_hidl@1.2", "libcodec2_hidl_plugin_stub", "libcodec2_hidl_plugin", + "libcodec2_hal_common", "libstagefright_bufferqueue_helper_novndk", "libGLESv2", "libEGL", @@ -763,6 +799,7 @@ var ( // Mainline Module Apps "CaptivePortalLogin", + "ModuleMetadata", "libstagefright_headers", @@ -805,6 +842,14 @@ 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", + + "merge_annotation_zips_test", } Bp2buildModuleTypeAlwaysConvertList = []string{ @@ -828,6 +873,10 @@ var ( // the "prebuilt_" prefix to the name, so that it's differentiable from // the source versions within Soong's module graph. Bp2buildModuleDoNotConvertList = []string{ + // TODO(b/263326760): Failed already. + "minijail_compiler_unittest", + "minijail_parser_unittest", + // Depends on unconverted libandroid, libgui "dvr_buffer_queue-test", "dvr_display-test", @@ -909,13 +958,15 @@ 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 "libdebuggerd_handler_core", "libdebuggerd_handler_fallback", // depends on unconverted module libdebuggerd "libdexfiled", // depends on unconverted modules: dexfile_operator_srcs, libartbased, libartpalette - "libfastdeploy_host", // depends on unconverted modules: libandroidfw, libusb, AdbWinApi "libgmock_main_ndk", // depends on unconverted modules: libgtest_ndk_c++ "libgmock_ndk", // depends on unconverted modules: libgtest_ndk_c++ "libnativehelper_lazy_mts_jni", "libnativehelper_mts_jni", // depends on unconverted modules: libnativetesthelper_jni, libgmock_ndk @@ -931,9 +982,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", @@ -972,8 +1020,6 @@ var ( "svcenc", "svcdec", // Failing host cc_tests - "libprocinfo_test", - "ziparchive-tests", "gtest_isolated_tests", "libunwindstack_unit_test", "power_tests", // failing test on server, but not on host @@ -992,7 +1038,7 @@ var ( "libnativebridge6-test-case", "libnativebridge6prezygotefork", - "libandroidfw_tests", "aapt2_tests", // failing due to data path issues + "libandroidfw_tests", // failing due to data path issues // error: overriding commands for target // `out/host/linux-x86/nativetest64/gmock_tests/gmock_tests__cc_runner_test', @@ -1016,6 +1062,7 @@ var ( "bionic-unit-tests-static", "boringssl_crypto_test", "boringssl_ssl_test", + "boringssl_test_support", //b/244431896 "cfi_test_helper", "cfi_test_helper2", "cintltst32", @@ -1049,6 +1096,7 @@ var ( "ion-unit-tests", "jemalloc5_integrationtests", "jemalloc5_unittests", + "jemalloc5_stresstests", // run by run_jemalloc_tests.sh and will be deleted after V "ld_config_test_helper", "ld_preload_test_helper", "libBionicCtsGtestMain", // depends on unconverted modules: libgtest_isolated @@ -1078,7 +1126,6 @@ var ( "memunreachable_binder_test", // depends on unconverted modules: libbinder "memunreachable_test", "metadata_tests", - "minijail0_cli_unittest_gtest", "mpeg2dec", "mvcdec", "ns_hidden_child_helper", @@ -1090,14 +1137,12 @@ var ( "rappor-tests", // depends on unconverted modules: jsr305, guava "scudo_unit_tests", "stats-log-api-gen-test", // depends on unconverted modules: libstats_proto_host - "syscall_filter_unittest_gtest", "thread_exit_cb_helper", "tls_properties_helper", "ulp", "vec_test", "yuvconstants", "yuvconvert", - "zipalign_tests", // cc_test_library "clang_diagnostic_tests", @@ -1493,8 +1538,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 @@ -1507,73 +1550,10 @@ var ( "libart_generated_headers", "libart-runtime-gtest", "libartd-runtime-gtest", - } + "libart-unstripped", - MixedBuildsDisabledList = []string{ - "libruy_static", "libtflite_kernel_utils", // TODO(b/237315968); Depend on prebuilt stl, not from source - - "art_libdexfile_dex_instruction_list_header", // breaks libart_mterp.armng, header not found - - "libbrotli", // http://b/198585397, ld.lld: error: bionic/libc/arch-arm64/generic/bionic/memmove.S:95:(.text+0x10): relocation R_AARCH64_CONDBR19 out of range: -1404176 is not in [-1048576, 1048575]; references __memcpy - "minijail_constants_json", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module. - - "cap_names.h", // TODO(b/204913827) runfiles need to be handled in mixed builds - "libcap", // TODO(b/204913827) runfiles need to be handled in mixed builds - "libprotobuf-cpp-full", "libprotobuf-cpp-lite", // Unsupported product&vendor suffix. b/204811222 and b/204810610. - - // Depends on libprotobuf-cpp-* - "libadb_pairing_connection", - "libadb_pairing_connection_static", - "libadb_pairing_server", "libadb_pairing_server_static", - - // java_import[_host] issues - // tradefed prebuilts depend on libprotobuf - "prebuilt_tradefed", - "prebuilt_tradefed-test-framework", - // handcrafted BUILD.bazel files in //prebuilts/... - "prebuilt_r8lib-prebuilt", - "prebuilt_sdk-core-lambda-stubs", - "prebuilt_android-support-collections-nodeps", - "prebuilt_android-arch-core-common-nodeps", - "prebuilt_android-arch-lifecycle-common-java8-nodeps", - "prebuilt_android-arch-lifecycle-common-nodeps", - "prebuilt_android-support-annotations-nodeps", - "prebuilt_android-arch-paging-common-nodeps", - "prebuilt_android-arch-room-common-nodeps", - // TODO(b/217750501) exclude_dirs property not supported - "prebuilt_kotlin-reflect", - "prebuilt_kotlin-stdlib", - "prebuilt_kotlin-stdlib-jdk7", - "prebuilt_kotlin-stdlib-jdk8", - "prebuilt_kotlin-test", - // TODO(b/217750501) exclude_files property not supported - "prebuilt_currysrc_org.eclipse", - - // TODO(b/266459895): re-enable libunwindstack - "libunwindstack", - "libunwindstack_stdout_log", - "libunwindstack_no_dex", - "libunwindstack_utils", - "unwind_reg_info", - "libunwindstack_local", - "unwind_for_offline", - "unwind", - "unwind_info", - "unwind_symbols", - "libEGL", - "libGLESv2", - "libc_malloc_debug", - "libcodec2_hidl@1.0", - "libcodec2_hidl@1.1", - "libcodec2_hidl@1.2", - "libfdtrack", - "libgui", - "libgui_bufferqueue_static", - "libmedia_codecserviceregistrant", - "libstagefright_bufferqueue_helper_novndk", - "libutils_test", - "libutilscallstack", - "mediaswcodec", + // depends on libart-unstripped and new module type llvm_prebuilt_build_tool + "check_cfi", } // Bazel prod-mode allowlist. Modules in this list are built by Bazel @@ -1598,6 +1578,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 +1590,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 +1598,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", @@ -1638,4 +1616,14 @@ var ( "art_": DEFAULT_PRIORITIZED_WEIGHT, "ndk_library": DEFAULT_PRIORITIZED_WEIGHT, } + + BazelSandwichTargets = []struct { + Label string + Host bool + }{ + { + Label: "//build/bazel/examples/partitions:system_image", + Host: false, + }, + } ) diff --git a/android/api_levels.go b/android/api_levels.go index 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/arch.go b/android/arch.go index 4b4691b3d..152016cd1 100644 --- a/android/arch.go +++ b/android/arch.go @@ -1884,10 +1884,10 @@ func decodeMultilibTargets(multilib string, targets []Target, prefer32 bool) ([] buildTargets = filterMultilibTargets(targets, "lib64") // Reverse the targets so that the first architecture can depend on the second // architecture module in order to merge the outputs. - reverseSliceInPlace(buildTargets) + ReverseSliceInPlace(buildTargets) case "darwin_universal_common_first": archTargets := filterMultilibTargets(targets, "lib64") - reverseSliceInPlace(archTargets) + ReverseSliceInPlace(archTargets) buildTargets = append(getCommonTargets(targets), archTargets...) default: return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", "64", "prefer32" or "first_prefer32" found %q`, diff --git a/android/bazel.go b/android/bazel.go index 1bfbdec00..e4fada0fe 100644 --- a/android/bazel.go +++ b/android/bazel.go @@ -21,7 +21,9 @@ import ( "strings" "android/soong/ui/metrics/bp2build_metrics_proto" + "github.com/google/blueprint" + "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/proptools" "android/soong/android/allowlists" @@ -152,8 +154,8 @@ type Bazelable interface { HasHandcraftedLabel() bool HandcraftedLabel() string GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string - ShouldConvertWithBp2build(ctx BazelConversionContext) bool - shouldConvertWithBp2build(ctx bazelOtherModuleContext, module blueprint.Module) bool + ShouldConvertWithBp2build(ctx ShouldConvertWithBazelContext) bool + shouldConvertWithBp2build(shouldConvertModuleContext, shouldConvertParams) bool // ConvertWithBp2build either converts the module to a Bazel build target or // declares the module as unconvertible (for logging and metrics). @@ -255,7 +257,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 { @@ -426,18 +428,53 @@ func MixedBuildsEnabled(ctx BaseModuleContext) MixedBuildEnabledStatus { return ModuleIncompatibility } +func isGoModule(module blueprint.Module) bool { + if _, ok := module.(*bootstrap.GoPackage); ok { + return true + } + if _, ok := module.(*bootstrap.GoBinary); ok { + return true + } + return false +} + // ConvertedToBazel returns whether this module has been converted (with bp2build or manually) to Bazel. func convertedToBazel(ctx BazelConversionContext, module blueprint.Module) bool { + // Special-case bootstrap_go_package and bootstrap_go_binary + // These do not implement Bazelable, but have been converted + if isGoModule(module) { + return true + } b, ok := module.(Bazelable) if !ok { return false } - return b.shouldConvertWithBp2build(ctx, module) || b.HasHandcraftedLabel() + + return b.HasHandcraftedLabel() || b.shouldConvertWithBp2build(ctx, shouldConvertParams{ + module: module, + moduleDir: ctx.OtherModuleDir(module), + moduleName: ctx.OtherModuleName(module), + moduleType: ctx.OtherModuleType(module), + }) +} + +type ShouldConvertWithBazelContext interface { + ModuleErrorf(format string, args ...interface{}) + Module() Module + Config() Config + ModuleType() string + ModuleName() string + ModuleDir() string } // ShouldConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build -func (b *BazelModuleBase) ShouldConvertWithBp2build(ctx BazelConversionContext) bool { - return b.shouldConvertWithBp2build(ctx, ctx.Module()) +func (b *BazelModuleBase) ShouldConvertWithBp2build(ctx ShouldConvertWithBazelContext) bool { + return b.shouldConvertWithBp2build(ctx, shouldConvertParams{ + module: ctx.Module(), + moduleDir: ctx.ModuleDir(), + moduleName: ctx.ModuleName(), + moduleType: ctx.ModuleType(), + }) } type bazelOtherModuleContext interface { @@ -455,11 +492,24 @@ func isPlatformIncompatible(osType OsType, arch ArchType) bool { arch == Riscv64 // TODO(b/262192655) Riscv64 toolchains are not currently supported. } -func (b *BazelModuleBase) shouldConvertWithBp2build(ctx bazelOtherModuleContext, module blueprint.Module) bool { +type shouldConvertModuleContext interface { + ModuleErrorf(format string, args ...interface{}) + Config() Config +} + +type shouldConvertParams struct { + module blueprint.Module + moduleType string + moduleDir string + moduleName string +} + +func (b *BazelModuleBase) shouldConvertWithBp2build(ctx shouldConvertModuleContext, p shouldConvertParams) bool { if !b.bazelProps().Bazel_module.CanConvertToBazel { return false } + module := p.module // In api_bp2build mode, all soong modules that can provide API contributions should be converted // This is irrespective of its presence/absence in bp2build allowlists if ctx.Config().BuildMode == ApiBp2build { @@ -468,7 +518,7 @@ func (b *BazelModuleBase) shouldConvertWithBp2build(ctx bazelOtherModuleContext, } propValue := b.bazelProperties.Bazel_module.Bp2build_available - packagePath := moduleDirWithPossibleOverride(ctx, module) + packagePath := moduleDirWithPossibleOverride(ctx, module, p.moduleDir) // Modules in unit tests which are enabled in the allowlist by type or name // trigger this conditional because unit tests run under the "." package path @@ -477,10 +527,10 @@ func (b *BazelModuleBase) shouldConvertWithBp2build(ctx bazelOtherModuleContext, return true } - moduleName := moduleNameWithPossibleOverride(ctx, module) + moduleName := moduleNameWithPossibleOverride(ctx, module, p.moduleName) allowlist := ctx.Config().Bp2buildPackageConfig moduleNameAllowed := allowlist.moduleAlwaysConvert[moduleName] - moduleTypeAllowed := allowlist.moduleTypeAlwaysConvert[ctx.OtherModuleType(module)] + moduleTypeAllowed := allowlist.moduleTypeAlwaysConvert[p.moduleType] allowlistConvert := moduleNameAllowed || moduleTypeAllowed if moduleNameAllowed && moduleTypeAllowed { ctx.ModuleErrorf("A module cannot be in moduleAlwaysConvert and also be in moduleTypeAlwaysConvert") @@ -572,8 +622,21 @@ func bp2buildConversionMutator(ctx TopDownMutatorContext) { ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "") return } + // There may be cases where the target is created by a macro rather than in a BUILD file, those + // should be captured as well. + if bModule.HasHandcraftedLabel() { + // Defer to the BUILD target. Generating an additional target would + // cause a BUILD file conflict. + ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE, "") + return + } // TODO: b/285631638 - Differentiate between denylisted modules and missing bp2build capabilities. - if !bModule.shouldConvertWithBp2build(ctx, ctx.Module()) { + if !bModule.shouldConvertWithBp2build(ctx, shouldConvertParams{ + module: ctx.Module(), + moduleDir: ctx.ModuleDir(), + moduleName: ctx.ModuleName(), + moduleType: ctx.ModuleType(), + }) { ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, "") return } diff --git a/android/bazel_handler.go b/android/bazel_handler.go index d5ccfcad8..fda8a2251 100644 --- a/android/bazel_handler.go +++ b/android/bazel_handler.go @@ -16,10 +16,13 @@ package android import ( "bytes" + "crypto/sha1" + "encoding/hex" "fmt" "os" "path" "path/filepath" + "regexp" "runtime" "sort" "strings" @@ -184,6 +187,8 @@ type BazelContext interface { // Returns the depsets defined in Bazel's aquery response. AqueryDepsets() []bazel.AqueryDepset + + QueueBazelSandwichCqueryRequests(config Config) error } type bazelRunner interface { @@ -262,6 +267,10 @@ func (m MockBazelContext) QueueBazelRequest(label string, requestType cqueryRequ m.BazelRequests[key] = true } +func (m MockBazelContext) QueueBazelSandwichCqueryRequests(config Config) error { + panic("unimplemented") +} + func (m MockBazelContext) GetOutputFiles(label string, _ configKey) ([]string, error) { result, ok := m.LabelToOutputFiles[label] if !ok { @@ -422,6 +431,10 @@ func (n noopBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configK panic("unimplemented") } +func (n noopBazelContext) QueueBazelSandwichCqueryRequests(config Config) error { + panic("unimplemented") +} + func (n noopBazelContext) GetOutputFiles(_ string, _ configKey) ([]string, error) { panic("unimplemented") } @@ -1040,6 +1053,64 @@ var ( allBazelCommands = []bazelCommand{aqueryCmd, cqueryCmd, buildCmd} ) +func GetBazelSandwichCqueryRequests(config Config) ([]cqueryKey, error) { + result := make([]cqueryKey, 0, len(allowlists.BazelSandwichTargets)) + labelRegex := regexp.MustCompile("^@?//([a-zA-Z0-9/_-]+):[a-zA-Z0-9_-]+$") + // Note that bazel "targets" are different from soong "targets", the bazel targets are + // synonymous with soong modules, and soong targets are a configuration a module is built in. + for _, target := range allowlists.BazelSandwichTargets { + match := labelRegex.FindStringSubmatch(target.Label) + if match == nil { + return nil, fmt.Errorf("invalid label, must match `^@?//([a-zA-Z0-9/_-]+):[a-zA-Z0-9_-]+$`: %s", target.Label) + } + if _, err := os.Stat(absolutePath(match[1])); err != nil { + if os.IsNotExist(err) { + // Ignore bazel sandwich targets that don't exist. + continue + } else { + return nil, err + } + } + + var soongTarget Target + if target.Host { + soongTarget = config.BuildOSTarget + } else { + soongTarget = config.AndroidCommonTarget + if soongTarget.Os.Class != Device { + // kernel-build-tools seems to set the AndroidCommonTarget to a linux host + // target for some reason, disable device builds in that case. + continue + } + } + + result = append(result, cqueryKey{ + label: target.Label, + requestType: cquery.GetOutputFiles, + configKey: configKey{ + arch: soongTarget.Arch.String(), + osType: soongTarget.Os, + }, + }) + } + return result, nil +} + +// QueueBazelSandwichCqueryRequests queues cquery requests for all the bazel labels in +// bazel_sandwich_targets. These will later be given phony targets so that they can be built on the +// command line. +func (context *mixedBuildBazelContext) QueueBazelSandwichCqueryRequests(config Config) error { + requests, err := GetBazelSandwichCqueryRequests(config) + if err != nil { + return err + } + for _, request := range requests { + context.QueueBazelRequest(request.label, request.requestType, request.configKey) + } + + return nil +} + // Issues commands to Bazel to receive results for all cquery requests // queued in the BazelContext. func (context *mixedBuildBazelContext) InvokeBazel(config Config, ctx invokeBazelContext) error { @@ -1222,7 +1293,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 { @@ -1249,6 +1324,11 @@ func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) { executionRoot := path.Join(ctx.Config().BazelContext.OutputBase(), "execroot", "__main__") bazelOutDir := path.Join(executionRoot, "bazel-out") + rel, err := filepath.Rel(ctx.Config().OutDir(), executionRoot) + if err != nil { + ctx.Errorf("%s", err.Error()) + } + dotdotsToOutRoot := strings.Repeat("../", strings.Count(rel, "/")+1) for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() { // nil build statements are a valid case where we do not create an action because it is // unnecessary or handled by other processing @@ -1257,7 +1337,31 @@ 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, dotdotsToOutRoot) + desc := fmt.Sprintf("%s: %s", buildStatement.Mnemonic, buildStatement.OutputPaths) rule.Build(fmt.Sprintf("bazel %d", index), desc) continue @@ -1270,6 +1374,12 @@ func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) { // because this would cause circular dependency. So, until we move aquery processing // to the 'android' package, we need to handle special cases here. switch buildStatement.Mnemonic { + case "RepoMappingManifest": + // It appears RepoMappingManifest files currently have + // non-deterministic content. Just emit empty files for + // now because they're unused. + out := PathForBazelOut(ctx, buildStatement.OutputPaths[0]) + WriteFileRuleVerbatim(ctx, out, "") case "FileWrite", "SourceSymlinkManifest": out := PathForBazelOut(ctx, buildStatement.OutputPaths[0]) WriteFileRuleVerbatim(ctx, out, buildStatement.FileContents) @@ -1296,12 +1406,45 @@ func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) { panic(fmt.Sprintf("unhandled build statement: %v", buildStatement)) } } + + // Create phony targets for all the bazel sandwich output files + requests, err := GetBazelSandwichCqueryRequests(ctx.Config()) + if err != nil { + ctx.Errorf(err.Error()) + } + for _, request := range requests { + files, err := ctx.Config().BazelContext.GetOutputFiles(request.label, request.configKey) + if err != nil { + ctx.Errorf(err.Error()) + } + filesAsPaths := make([]Path, 0, len(files)) + for _, file := range files { + filesAsPaths = append(filesAsPaths, PathForBazelOut(ctx, file)) + } + ctx.Phony("bazel_sandwich", filesAsPaths...) + } + ctx.Phony("checkbuild", PathForPhony(ctx, "bazel_sandwich")) +} + +// Returns a out dir path for a sandboxed mixed build action +func intermediatePathForSboxMixedBuildAction(ctx PathContext, statement *bazel.BuildStatement) (OutputPath, string) { + // An artifact can be generated by a single buildstatement. + // Use the hash of the first artifact to create a unique path + uniqueDir := sha1.New() + uniqueDir.Write([]byte(statement.OutputPaths[0])) + uniqueDirHashString := hex.EncodeToString(uniqueDir.Sum(nil)) + return PathForOutput(ctx, "mixed_build_sbox_intermediates", uniqueDirHashString), uniqueDirHashString } // Register bazel-owned build statements (obtained from the aquery invocation). -func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx BuilderContext) { +func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx BuilderContext, depsetHashToDepset map[string]bazel.AqueryDepset, dotdotsToOutRoot string) { // executionRoot is the action cwd. - cmd.Text(fmt.Sprintf("cd '%s' &&", executionRoot)) + if buildStatement.ShouldRunInSbox { + // mkdir -p ensures that the directory exists when run via sbox + cmd.Text(fmt.Sprintf("mkdir -p '%s' && cd '%s' &&", executionRoot, executionRoot)) + } else { + cmd.Text(fmt.Sprintf("cd '%s' &&", executionRoot)) + } // Remove old outputs, as some actions might not rerun if the outputs are detected. if len(buildStatement.OutputPaths) > 0 { @@ -1317,25 +1460,47 @@ func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement cmd.Flag(pair.Key + "=" + pair.Value) } + command := buildStatement.Command + command = strings.ReplaceAll(command, "{DOTDOTS_TO_OUTPUT_ROOT}", dotdotsToOutRoot) + // The actual Bazel action. - if len(buildStatement.Command) > 16*1024 { + if len(command) > 16*1024 { commandFile := PathForBazelOut(ctx, buildStatement.OutputPaths[0]+".sh") - WriteFileRule(ctx, commandFile, buildStatement.Command) + WriteFileRule(ctx, commandFile, command) cmd.Text("bash").Text(buildStatement.OutputPaths[0] + ".sh").Implicit(commandFile) } else { - cmd.Text(buildStatement.Command) + cmd.Text(command) } for _, outputPath := range buildStatement.OutputPaths { - cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath)) + if buildStatement.ShouldRunInSbox { + // The full path has three components that get joined together + // 1. intermediate output dir that `sbox` will place the artifacts at + // 2. mixed build execution root + // 3. artifact path returned by aquery + intermediateDir, _ := intermediatePathForSboxMixedBuildAction(ctx, buildStatement) + cmd.ImplicitOutput(intermediateDir.Join(ctx, executionRoot, outputPath)) + } else { + cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath)) + } } for _, inputPath := range buildStatement.InputPaths { cmd.Implicit(PathForBazelOut(ctx, inputPath)) } for _, inputDepsetHash := range buildStatement.InputDepsetHashes { - otherDepsetName := bazelDepsetName(inputDepsetHash) - cmd.Implicit(PathForPhony(ctx, otherDepsetName)) + if buildStatement.ShouldRunInSbox { + // Bazel depsets are phony targets that are used to group files. + // We need to copy the grouped files into the sandbox + ds, _ := depsetHashToDepset[inputDepsetHash] + cmd.Implicits(PathsForBazelOut(ctx, ds.DirectArtifacts)) + } else { + otherDepsetName := bazelDepsetName(inputDepsetHash) + cmd.Implicit(PathForPhony(ctx, otherDepsetName)) + } + } + for _, implicitPath := range buildStatement.ImplicitDeps { + cmd.Implicit(PathForArbitraryOutput(ctx, implicitPath)) } if depfile := buildStatement.Depfile; depfile != nil { diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go index 65cd5a836..9a3c8fc7c 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..02ae5ca20 100644 --- a/android/bazel_paths.go +++ b/android/bazel_paths.go @@ -88,6 +88,8 @@ type BazelConversionPathContext interface { EarlyModulePathContext BazelConversionContext + ModuleName() string + ModuleType() string ModuleErrorf(fmt string, args ...interface{}) PropertyErrorf(property, fmt string, args ...interface{}) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) @@ -124,6 +126,7 @@ func BazelLabelForModuleDepsWithFn(ctx BazelConversionPathContext, modules []str labels.Includes = []bazel.Label{} return labels } + modules = FirstUniqueStrings(modules) for _, module := range modules { bpText := module if m := SrcIsModule(module); m == "" { @@ -179,7 +182,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 +192,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 +201,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 +240,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 +284,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 +298,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 +316,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 +358,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{} @@ -375,7 +378,13 @@ func expandSrcsForBazel(ctx BazelConversionPathContext, paths, expandedExcludes if m, tag := SrcIsModuleWithTag(p); m != "" { l := getOtherModuleLabel(ctx, m, tag, BazelModuleLabel) if l != nil && !InList(l.Label, expandedExcludes) { - l.OriginalModuleName = fmt.Sprintf(":%s", m) + if strings.HasPrefix(m, "//") { + // this is a module in a soong namespace + // It appears as //<namespace>:<module_name> in srcs, and not ://<namespace>:<module_name> + l.OriginalModuleName = m + } else { + l.OriginalModuleName = fmt.Sprintf(":%s", m) + } labels.Includes = append(labels.Includes, *l) } } else { @@ -430,7 +439,7 @@ func getOtherModuleLabel(ctx BazelConversionPathContext, dep, tag string, func BazelModuleLabel(ctx BazelConversionPathContext, module blueprint.Module) string { // TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets. - if !convertedToBazel(ctx, module) { + if !convertedToBazel(ctx, module) || isGoModule(module) { return bp2buildModuleLabel(ctx, module) } b, _ := module.(Bazelable) @@ -458,8 +467,8 @@ func samePackage(label1, label2 string) bool { } func bp2buildModuleLabel(ctx BazelConversionContext, module blueprint.Module) string { - moduleName := moduleNameWithPossibleOverride(ctx, module) - moduleDir := moduleDirWithPossibleOverride(ctx, module) + moduleName := moduleNameWithPossibleOverride(ctx, module, ctx.OtherModuleName(module)) + moduleDir := moduleDirWithPossibleOverride(ctx, module, ctx.OtherModuleDir(module)) if moduleDir == Bp2BuildTopLevel { moduleDir = "" } diff --git a/android/bazel_paths_test.go b/android/bazel_paths_test.go index 450bf7674..75b77a36c 100644 --- a/android/bazel_paths_test.go +++ b/android/bazel_paths_test.go @@ -19,6 +19,7 @@ import ( "testing" "android/soong/bazel" + "github.com/google/blueprint" "github.com/google/blueprint/pathtools" ) @@ -157,6 +158,14 @@ func (ctx *TestBazelConversionPathContext) ModuleDir() string { return ctx.moduleDir } +func (ctx *TestBazelConversionPathContext) ModuleName() string { + panic("Unimplemented") +} + +func (ctx *TestBazelConversionPathContext) ModuleType() string { + panic("Unimplemented") +} + func TestTransformSubpackagePath(t *testing.T) { cfg := NullConfig("out", "out/soong") cfg.fs = pathtools.MockFs(map[string][]byte{ @@ -175,7 +184,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/bazel_test.go b/android/bazel_test.go index 13fd40849..194a6b359 100644 --- a/android/bazel_test.go +++ b/android/bazel_test.go @@ -373,7 +373,14 @@ func TestBp2BuildAllowlist(t *testing.T) { allowlist: test.allowlist, } - shouldConvert := test.module.shouldConvertWithBp2build(bcc, test.module.TestModuleInfo) + shouldConvert := test.module.shouldConvertWithBp2build(bcc, + shouldConvertParams{ + module: test.module.TestModuleInfo, + moduleDir: test.module.TestModuleInfo.Dir, + moduleType: test.module.TestModuleInfo.Typ, + moduleName: test.module.TestModuleInfo.ModuleName, + }, + ) if test.shouldConvert != shouldConvert { t.Errorf("Module shouldConvert expected to be: %v, but was: %v", test.shouldConvert, shouldConvert) } diff --git a/android/config.go b/android/config.go index fa439625d..3e7bb1426 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" @@ -171,6 +170,19 @@ func (c Config) RunningInsideUnitTest() bool { return c.config.TestProductVariables != nil } +// DisableHiddenApiChecks returns true if hiddenapi checks have been disabled. +// For 'eng' target variant hiddenapi checks are disabled by default for performance optimisation, +// but can be enabled by setting environment variable ENABLE_HIDDENAPI_FLAGS=true. +// For other target variants hiddenapi check are enabled by default but can be disabled by +// setting environment variable UNSAFE_DISABLE_HIDDENAPI_FLAGS=true. +// If both ENABLE_HIDDENAPI_FLAGS=true and UNSAFE_DISABLE_HIDDENAPI_FLAGS=true, then +// ENABLE_HIDDENAPI_FLAGS=true will be triggered and hiddenapi checks will be considered enabled. +func (c Config) DisableHiddenApiChecks() bool { + return !c.IsEnvTrue("ENABLE_HIDDENAPI_FLAGS") && + (c.IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") || + Bool(c.productVariables.Eng)) +} + // MaxPageSizeSupported returns the max page size supported by the device. This // value will define the ELF segment alignment for binaries (executables and // shared libraries). @@ -178,6 +190,12 @@ func (c Config) MaxPageSizeSupported() string { return String(c.config.productVariables.DeviceMaxPageSizeSupported) } +// PageSizeAgnostic returns true when AOSP is page size agnostic, +// othersise it returns false. +func (c Config) PageSizeAgnostic() bool { + return Bool(c.config.productVariables.DevicePageSizeAgnostic) +} + // The release version passed to aconfig, derived from RELEASE_VERSION func (c Config) ReleaseVersion() string { return c.config.productVariables.ReleaseVersion @@ -188,6 +206,12 @@ func (c Config) ReleaseAconfigValueSets() []string { return c.config.productVariables.ReleaseAconfigValueSets } +// The flag default permission value passed to aconfig +// derived from RELEASE_ACONFIG_FLAG_DEFAULT_PERMISSION +func (c Config) ReleaseAconfigFlagDefaultPermission() string { + return c.config.productVariables.ReleaseAconfigFlagDefaultPermission +} + // A DeviceConfig object represents the configuration for a particular device // being built. For now there will only be one of these, but in the future there // may be multiple devices being built. @@ -202,10 +226,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 +345,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 +397,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,65 +426,52 @@ func saveToConfigFile(config *productVariables, filename string) error { return nil } -func saveToBazelConfigFile(config *productVariables, outDir string) error { +type productVariableStarlarkRepresentation struct { + soongType string + selectable bool + archVariant bool +} + +func saveToBazelConfigFile(config *ProductVariables, outDir string) error { dir := filepath.Join(outDir, bazel.SoongInjectionDirName, "product_config") err := createDirIfNonexistent(dir, os.ModePerm) if err != nil { return fmt.Errorf("Could not create dir %s: %s", dir, err) } - nonArchVariantProductVariables := []string{} - archVariantProductVariables := []string{} + allProductVariablesType := reflect.TypeOf((*ProductVariables)(nil)).Elem() + productVariablesInfo := make(map[string]productVariableStarlarkRepresentation) p := variableProperties{} t := reflect.TypeOf(p.Product_variables) for i := 0; i < t.NumField(); i++ { f := t.Field(i) - nonArchVariantProductVariables = append(nonArchVariantProductVariables, strings.ToLower(f.Name)) - if proptools.HasTag(f, "android", "arch_variant") { - archVariantProductVariables = append(archVariantProductVariables, strings.ToLower(f.Name)) + archVariant := proptools.HasTag(f, "android", "arch_variant") + if mainProductVariablesStructField, ok := allProductVariablesType.FieldByName(f.Name); ok { + productVariablesInfo[f.Name] = productVariableStarlarkRepresentation{ + soongType: stringRepresentationOfSimpleType(mainProductVariablesStructField.Type), + selectable: true, + archVariant: archVariant, + } + } else { + panic("Unknown variable " + f.Name) } } - nonArchVariantProductVariablesJson := starlark_fmt.PrintStringList(nonArchVariantProductVariables, 0) - if err != nil { - return fmt.Errorf("cannot marshal product variable data: %s", err.Error()) - } - - archVariantProductVariablesJson := starlark_fmt.PrintStringList(archVariantProductVariables, 0) - if err != nil { - 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 -`, nonArchVariantProductVariablesJson, archVariantProductVariablesJson)), 0644) +# product_var_constant_info is a map of product variables to information about them. The fields are: +# - soongType: The type of the product variable as it appears in soong's ProductVariables struct. +# examples are string, bool, int, *bool, *string, []string, etc. This may be an overly +# conservative estimation of the type, for example a *bool could oftentimes just be a +# bool that defaults to false. +# - selectable: if this product variable can be selected on in Android.bp/build files. This means +# it's listed in the "variableProperties" soong struct. Currently all variables in +# this list are selectable because we only need the selectable ones at the moment, +# but the list may be expanded later. +# - archVariant: If the variable is tagged as arch variant in the "variableProperties" struct. +product_var_constant_info = %s +product_var_constraints = [k for k, v in product_var_constant_info.items() if v.selectable] +arch_variant_product_var_constraints = [k for k, v in product_var_constant_info.items() if v.selectable and v.archVariant] +`, starlark_fmt.PrintAny(productVariablesInfo, 0))), 0644) if err != nil { return fmt.Errorf("Could not write .bzl config file %s", err) } @@ -473,6 +484,23 @@ arch_variant_product_var_constraints = %s return nil } +func stringRepresentationOfSimpleType(ty reflect.Type) string { + switch ty.Kind() { + case reflect.String: + return "string" + case reflect.Bool: + return "bool" + case reflect.Int: + return "int" + case reflect.Slice: + return "[]" + stringRepresentationOfSimpleType(ty.Elem()) + case reflect.Pointer: + return "*" + stringRepresentationOfSimpleType(ty.Elem()) + default: + panic("unimplemented type: " + ty.Kind().String()) + } +} + // NullConfig returns a mostly empty Config for use by standalone tools like dexpreopt_gen that // use the android package. func NullConfig(outDir, soongOutDir string) Config { @@ -1355,6 +1383,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 +1964,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/depset_generic.go b/android/depset_generic.go index 4f31b8697..45c193715 100644 --- a/android/depset_generic.go +++ b/android/depset_generic.go @@ -79,8 +79,8 @@ func NewDepSet[T depSettableType](order DepSetOrder, direct []T, transitive []*D if order == TOPOLOGICAL { // TOPOLOGICAL is implemented as a postorder traversal followed by reversing the output. // Pre-reverse the inputs here so their order is maintained in the output. - directCopy = reverseSlice(direct) - transitiveCopy = reverseSlice(transitive) + directCopy = ReverseSlice(direct) + transitiveCopy = ReverseSlice(transitive) } else { directCopy = append([]T(nil), direct...) transitiveCopy = append([]*DepSet[T](nil), transitive...) @@ -184,7 +184,7 @@ func (d *DepSet[T]) ToList() []T { }) list = firstUniqueInPlace(list) if d.reverse { - reverseSliceInPlace(list) + ReverseSliceInPlace(list) } return list } diff --git a/android/filegroup.go b/android/filegroup.go index 3b866550d..6cc9232b6 100644 --- a/android/filegroup.go +++ b/android/filegroup.go @@ -24,6 +24,7 @@ import ( "android/soong/ui/metrics/bp2build_metrics_proto" "github.com/google/blueprint" + "github.com/google/blueprint/proptools" ) func init() { @@ -141,8 +142,14 @@ func (fg *fileGroup) ConvertWithBp2build(ctx TopDownMutatorContext) { attrs) } else { if fg.ShouldConvertToProtoLibrary(ctx) { + pkgToSrcs := partitionSrcsByPackage(ctx.ModuleDir(), bazel.MakeLabelList(srcs.Value.Includes)) + if len(pkgToSrcs) > 1 { + ctx.ModuleErrorf("TODO: Add bp2build support for multiple package .protosrcs in filegroup") + return + } + pkg := SortedKeys(pkgToSrcs)[0] attrs := &ProtoAttrs{ - Srcs: srcs, + Srcs: bazel.MakeLabelListAttribute(pkgToSrcs[pkg]), Strip_import_prefix: fg.properties.Path, } @@ -151,13 +158,39 @@ func (fg *fileGroup) ConvertWithBp2build(ctx TopDownMutatorContext) { // TODO(b/246997908): we can remove this tag if we could figure out a solution for this bug. "manual", } + if pkg != ctx.ModuleDir() { + // Since we are creating the proto_library in a subpackage, create an import_prefix relative to the current package + if rel, err := filepath.Rel(ctx.ModuleDir(), pkg); err != nil { + ctx.ModuleErrorf("Could not get relative path for %v %v", pkg, err) + } else if rel != "." { + attrs.Import_prefix = &rel + // Strip the package prefix + attrs.Strip_import_prefix = proptools.StringPtr("") + } + } + ctx.CreateBazelTargetModule( bazel.BazelTargetModuleProperties{Rule_class: "proto_library"}, CommonAttributes{ - Name: fg.Name() + convertedProtoLibrarySuffix, + Name: fg.Name() + "_proto", + Dir: proptools.StringPtr(pkg), Tags: bazel.MakeStringListAttribute(tags), }, attrs) + + // Create an alias in the current dir. The actual target might exist in a different package, but rdeps + // can reliabily use this alias + ctx.CreateBazelTargetModule( + bazel.BazelTargetModuleProperties{Rule_class: "alias"}, + CommonAttributes{ + Name: fg.Name() + convertedProtoLibrarySuffix, + // TODO(b/246997908): we can remove this tag if we could figure out a solution for this bug. + Tags: bazel.MakeStringListAttribute(tags), + }, + &bazelAliasAttributes{ + Actual: bazel.MakeLabelAttribute("//" + pkg + ":" + fg.Name() + "_proto"), + }, + ) } // TODO(b/242847534): Still convert to a filegroup because other unconverted 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..19502bae8 100644 --- a/android/module.go +++ b/android/module.go @@ -1021,6 +1021,11 @@ type CommonAttributes struct { Applicable_licenses bazel.LabelListAttribute Testonly *bool + + // Dir is neither a Soong nor Bazel target attribute + // If set, the bazel target will be created in this directory + // If unset, the bazel target will default to be created in the directory of the visited soong module + Dir *string } // constraintAttributes represents Bazel attributes pertaining to build constraints, @@ -1373,15 +1378,15 @@ func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutator } } - productConfigEnabledLabels := []bazel.Label{} + productConfigEnabledAttribute := bazel.LabelListAttribute{} // TODO(b/234497586): Soong config variables and product variables have different overriding behavior, we // should handle it correctly if !proptools.BoolDefault(enabledProperty.Value, true) && !neitherHostNorDevice { // If the module is not enabled by default, then we can check if a // product variable enables it - productConfigEnabledLabels = productVariableConfigEnableLabels(ctx) + productConfigEnabledAttribute = productVariableConfigEnableAttribute(ctx) - if len(productConfigEnabledLabels) > 0 { + if len(productConfigEnabledAttribute.ConfigurableValues) > 0 { // In this case, an existing product variable configuration overrides any // module-level `enable: false` definition newValue := true @@ -1389,10 +1394,6 @@ func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutator } } - productConfigEnabledAttribute := bazel.MakeLabelListAttribute(bazel.LabelList{ - productConfigEnabledLabels, nil, - }) - platformEnabledAttribute, err := enabledProperty.ToLabelListAttribute( bazel.LabelList{[]bazel.Label{{Label: "@platforms//:incompatible"}}, nil}, bazel.LabelList{[]bazel.Label{}, nil}) @@ -1423,31 +1424,35 @@ func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutator // Check product variables for `enabled: true` flag override. // Returns a list of the constraint_value targets who enable this override. -func productVariableConfigEnableLabels(ctx *topDownMutatorContext) []bazel.Label { +func productVariableConfigEnableAttribute(ctx *topDownMutatorContext) bazel.LabelListAttribute { + result := bazel.LabelListAttribute{} productVariableProps := ProductVariableProperties(ctx, ctx.Module()) - productConfigEnablingTargets := []bazel.Label{} - const propName = "Enabled" - if productConfigProps, exists := productVariableProps[propName]; exists { + if productConfigProps, exists := productVariableProps["Enabled"]; exists { for productConfigProp, prop := range productConfigProps { flag, ok := prop.(*bool) if !ok { - ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName)) + ctx.ModuleErrorf("Could not convert product variable enabled property") } - if *flag { + if flag == nil { + // soong config var is not used to set `enabled`. nothing to do. + continue + } else if *flag { axis := productConfigProp.ConfigurationAxis() - targetLabel := axis.SelectKey(productConfigProp.SelectKey()) - productConfigEnablingTargets = append(productConfigEnablingTargets, bazel.Label{ - Label: targetLabel, - }) + result.SetSelectValue(axis, bazel.ConditionsDefaultConfigKey, bazel.MakeLabelList([]bazel.Label{{Label: "@platforms//:incompatible"}})) + result.SetSelectValue(axis, productConfigProp.SelectKey(), bazel.LabelList{Includes: []bazel.Label{}}) + } else if scp, isSoongConfigProperty := productConfigProp.(SoongConfigProperty); isSoongConfigProperty && scp.value == bazel.ConditionsDefaultConfigKey { + // productVariableConfigEnableAttribute runs only if `enabled: false` is set at the top-level outside soong_config_variables + // conditions_default { enabled: false} is a no-op in this case + continue } else { // TODO(b/210546943): handle negative case where `enabled: false` - ctx.ModuleErrorf("`enabled: false` is not currently supported for configuration variables. See b/210546943", proptools.PropertyNameForField(propName)) + ctx.ModuleErrorf("`enabled: false` is not currently supported for configuration variables. See b/210546943") } } } - return productConfigEnablingTargets + return result } // A ModuleBase object contains the properties that are common to all Android @@ -4029,43 +4034,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/mutator.go b/android/mutator.go index 2ec051e59..6bcac93c1 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -17,6 +17,7 @@ package android import ( "android/soong/bazel" "android/soong/ui/metrics/bp2build_metrics_proto" + "path/filepath" "github.com/google/blueprint" ) @@ -757,6 +758,27 @@ func (t *topDownMutatorContext) CreateBazelTargetAliasInDir( mod.base().addBp2buildInfo(info) } +// Returns the directory in which the bazel target will be generated +// If ca.Dir is not nil, use that +// Otherwise default to the directory of the soong module +func dirForBazelTargetGeneration(t *topDownMutatorContext, ca *CommonAttributes) string { + dir := t.OtherModuleDir(t.Module()) + if ca.Dir != nil { + dir = *ca.Dir + // Restrict its use to dirs that contain an Android.bp file. + // There are several places in bp2build where we use the existence of Android.bp/BUILD on the filesystem + // to curate a compatible label for src files (e.g. headers for cc). + // If we arbritrarily create BUILD files, then it might render those curated labels incompatible. + if exists, _, _ := t.Config().fs.Exists(filepath.Join(dir, "Android.bp")); !exists { + t.ModuleErrorf("Cannot use ca.Dir to create a BazelTarget in dir: %v since it does not contain an Android.bp file", dir) + } + + // Set ca.Dir to nil so that it does not get emitted to the BUILD files + ca.Dir = nil + } + return dir +} + func (t *topDownMutatorContext) CreateBazelConfigSetting( csa bazel.ConfigSettingAttributes, ca CommonAttributes, @@ -851,7 +873,7 @@ func (t *topDownMutatorContext) createBazelTargetModule( constraintAttributes := commonAttrs.fillCommonBp2BuildModuleAttrs(t, enabledProperty) mod := t.Module() info := bp2buildInfo{ - Dir: t.OtherModuleDir(mod), + Dir: dirForBazelTargetGeneration(t, &commonAttrs), BazelProps: bazelProps, CommonAttrs: commonAttrs, ConstraintAttrs: constraintAttributes, diff --git a/android/override_module.go b/android/override_module.go index a4b7431f6..9e0de6fd0 100644 --- a/android/override_module.go +++ b/android/override_module.go @@ -353,26 +353,26 @@ func replaceDepsOnOverridingModuleMutator(ctx BottomUpMutatorContext) { // variant of this OverridableModule, or ctx.ModuleName() if this module is not an OverridableModule // or if this variant is not overridden. func ModuleNameWithPossibleOverride(ctx BazelConversionContext) string { - return moduleNameWithPossibleOverride(ctx, ctx.Module()) + return moduleNameWithPossibleOverride(ctx, ctx.Module(), ctx.OtherModuleName(ctx.Module())) } -func moduleNameWithPossibleOverride(ctx bazelOtherModuleContext, module blueprint.Module) string { +func moduleNameWithPossibleOverride(ctx shouldConvertModuleContext, module blueprint.Module, name string) string { if overridable, ok := module.(OverridableModule); ok { if o := overridable.GetOverriddenBy(); o != "" { return o } } - return ctx.OtherModuleName(module) + return name } // moduleDirWithPossibleOverride returns the dir of the OverrideModule that overrides the current // variant of the given OverridableModule, or ctx.OtherModuleName() if the module is not an // OverridableModule or if the variant is not overridden. -func moduleDirWithPossibleOverride(ctx bazelOtherModuleContext, module blueprint.Module) string { +func moduleDirWithPossibleOverride(ctx shouldConvertModuleContext, module blueprint.Module, dir string) string { if overridable, ok := module.(OverridableModule); ok { if o := overridable.GetOverriddenByModuleDir(); o != "" { return o } } - return ctx.OtherModuleDir(module) + return dir } diff --git a/android/paths.go b/android/paths.go index fda4d2f46..325a953c4 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, @@ -1029,16 +1029,16 @@ func (p basePath) withRel(rel string) basePath { return p } +func (p basePath) RelativeToTop() Path { + ensureTestOnly() + return p +} + // SourcePath is a Path representing a file path rooted from SrcDir type SourcePath struct { basePath } -func (p SourcePath) RelativeToTop() Path { - ensureTestOnly() - return p -} - var _ Path = SourcePath{} func (p SourcePath) withRel(rel string) SourcePath { @@ -1126,6 +1126,16 @@ func PathForSource(ctx PathContext, pathComponents ...string) SourcePath { return path } +// PathForArbitraryOutput creates a path for the given components. Unlike PathForOutput, +// the path is relative to the root of the output folder, not the out/soong folder. +func PathForArbitraryOutput(ctx PathContext, pathComponents ...string) Path { + p, err := validatePath(pathComponents...) + if err != nil { + reportPathError(ctx, err) + } + return basePath{path: filepath.Join(ctx.Config().OutDir(), p)} +} + // MaybeExistentPathForSource joins the provided path components and validates that the result // neither escapes the source dir nor is in the out dir. // It does not validate whether the path exists. diff --git a/android/prebuilt_build_tool.go b/android/prebuilt_build_tool.go index e5edf9129..aeae20f48 100644 --- a/android/prebuilt_build_tool.go +++ b/android/prebuilt_build_tool.go @@ -102,6 +102,10 @@ var _ HostToolProvider = &prebuiltBuildTool{} // prebuilt_build_tool is to declare prebuilts to be used during the build, particularly for use // in genrules with the "tools" property. func prebuiltBuildToolFactory() Module { + return NewPrebuiltBuildTool() +} + +func NewPrebuiltBuildTool() Module { module := &prebuiltBuildTool{} module.AddProperties(&module.properties) InitSingleSourcePrebuiltModule(module, &module.properties, "Src") diff --git a/android/proto.go b/android/proto.go index cebbd59cd..b21efd640 100644 --- a/android/proto.go +++ b/android/proto.go @@ -15,6 +15,7 @@ package android import ( + "path/filepath" "strings" "android/soong/bazel" @@ -156,12 +157,12 @@ func ProtoRule(rule *RuleBuilder, protoFile Path, flags ProtoFlags, deps Paths, // Bp2buildProtoInfo contains information necessary to pass on to language specific conversion. type Bp2buildProtoInfo struct { Type *string - Name string Proto_libs bazel.LabelList } type ProtoAttrs struct { Srcs bazel.LabelListAttribute + Import_prefix *string Strip_import_prefix *string Deps bazel.LabelListAttribute } @@ -172,6 +173,35 @@ var includeDirsToProtoDeps = map[string]string{ "external/protobuf/src": "//external/protobuf:libprotobuf-proto", } +// Partitions srcs by the pkg it is in +// srcs has been created using `TransformSubpackagePaths` +// This function uses existence of Android.bp/BUILD files to create a label that is compatible with the package structure of bp2build workspace +func partitionSrcsByPackage(currentDir string, srcs bazel.LabelList) map[string]bazel.LabelList { + getPackageFromLabel := func(label string) string { + // Remove any preceding // + label = strings.TrimPrefix(label, "//") + split := strings.Split(label, ":") + if len(split) == 1 { + // e.g. foo.proto + return currentDir + } else if split[0] == "" { + // e.g. :foo.proto + return currentDir + } else { + return split[0] + } + } + + pkgToSrcs := map[string]bazel.LabelList{} + for _, src := range srcs.Includes { + pkg := getPackageFromLabel(src.Label) + list := pkgToSrcs[pkg] + list.Add(&src) + pkgToSrcs[pkg] = list + } + return pkgToSrcs +} + // Bp2buildProtoProperties converts proto properties, creating a proto_library and returning the // information necessary for language-specific handling. func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs bazel.LabelListAttribute) (Bp2buildProtoInfo, bool) { @@ -197,54 +227,87 @@ func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs baz } } - info.Name = m.Name() + "_proto" + name := m.Name() + "_proto" - if len(directProtoSrcs.Includes) > 0 { - attrs := ProtoAttrs{ - Srcs: bazel.MakeLabelListAttribute(directProtoSrcs), - } - attrs.Deps.Append(bazel.MakeLabelListAttribute(protoLibraries)) - - for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) { - for _, rawProps := range configToProps { - var props *ProtoProperties - var ok bool - if props, ok = rawProps.(*ProtoProperties); !ok { - ctx.ModuleErrorf("Could not cast ProtoProperties to expected type") - } - if axis == bazel.NoConfigAxis { - info.Type = props.Proto.Type + depsFromFilegroup := protoLibraries + var canonicalPathFromRoot bool - if !proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault) { - // an empty string indicates to strips the package path - path := "" - attrs.Strip_import_prefix = &path + if len(directProtoSrcs.Includes) > 0 { + pkgToSrcs := partitionSrcsByPackage(ctx.ModuleDir(), directProtoSrcs) + for _, pkg := range SortedStringKeys(pkgToSrcs) { + srcs := pkgToSrcs[pkg] + attrs := ProtoAttrs{ + Srcs: bazel.MakeLabelListAttribute(srcs), + } + attrs.Deps.Append(bazel.MakeLabelListAttribute(depsFromFilegroup)) + + for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) { + for _, rawProps := range configToProps { + var props *ProtoProperties + var ok bool + if props, ok = rawProps.(*ProtoProperties); !ok { + ctx.ModuleErrorf("Could not cast ProtoProperties to expected type") } + if axis == bazel.NoConfigAxis { + info.Type = props.Proto.Type + + canonicalPathFromRoot = proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault) + if !canonicalPathFromRoot { + // an empty string indicates to strips the package path + path := "" + attrs.Strip_import_prefix = &path + } - for _, dir := range props.Proto.Include_dirs { - if dep, ok := includeDirsToProtoDeps[dir]; ok { - attrs.Deps.Add(bazel.MakeLabelAttribute(dep)) - } else { - ctx.PropertyErrorf("Could not find the proto_library target for include dir", dir) + for _, dir := range props.Proto.Include_dirs { + if dep, ok := includeDirsToProtoDeps[dir]; ok { + attrs.Deps.Add(bazel.MakeLabelAttribute(dep)) + } else { + ctx.PropertyErrorf("Could not find the proto_library target for include dir", dir) + } } + } else if props.Proto.Type != info.Type && props.Proto.Type != nil { + ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.") } - } else if props.Proto.Type != info.Type && props.Proto.Type != nil { - ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.") } } - } - tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module()) + tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module()) - ctx.CreateBazelTargetModule( - bazel.BazelTargetModuleProperties{Rule_class: "proto_library"}, - CommonAttributes{Name: info.Name, Tags: tags}, - &attrs, - ) + moduleDir := ctx.ModuleDir() + if !canonicalPathFromRoot { + // Since we are creating the proto_library in a subpackage, set the import_prefix relative to the current package + if rel, err := filepath.Rel(moduleDir, pkg); err != nil { + ctx.ModuleErrorf("Could not get relative path for %v %v", pkg, err) + } else if rel != "." { + attrs.Import_prefix = &rel + } + } - protoLibraries.Add(&bazel.Label{ - Label: ":" + info.Name, - }) + // TODO - b/246997908: Handle potential orphaned proto_library targets + // To create proto_library targets in the same package, we split the .proto files + // This means that if a proto_library in a subpackage imports another proto_library from the parent package + // (or a different subpackage), it will not find it. + // The CcProtoGen action itself runs fine because we construct the correct ProtoInfo, + // but the FileDescriptorSet of each proto_library might not be compile-able + if pkg != ctx.ModuleDir() { + tags.Append(bazel.MakeStringListAttribute([]string{"manual"})) + } + ctx.CreateBazelTargetModule( + bazel.BazelTargetModuleProperties{Rule_class: "proto_library"}, + CommonAttributes{Name: name, Dir: proptools.StringPtr(pkg), Tags: tags}, + &attrs, + ) + + l := "" + if pkg == moduleDir { // same package that the original module lives in + l = ":" + name + } else { + l = "//" + pkg + ":" + name + } + protoLibraries.Add(&bazel.Label{ + Label: l, + }) + } } info.Proto_libs = protoLibraries 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 50bf5aa54..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 { @@ -351,15 +349,19 @@ func firstUniqueMap[T comparable](in []T) []T { return in[0:writeIndex] } -// reverseSliceInPlace reverses the elements of a slice in place. -func reverseSliceInPlace[T any](in []T) { +// ReverseSliceInPlace reverses the elements of a slice in place and returns it. +func ReverseSliceInPlace[T any](in []T) []T { for i, j := 0, len(in)-1; i < j; i, j = i+1, j-1 { in[i], in[j] = in[j], in[i] } + return in } -// reverseSlice returns a copy of a slice in reverse order. -func reverseSlice[T any](in []T) []T { +// ReverseSlice returns a copy of a slice in reverse order. +func ReverseSlice[T any](in []T) []T { + if in == nil { + return in + } out := make([]T, len(in)) for i := 0; i < len(in); i++ { out[i] = in[len(in)-1-i] diff --git a/android/util_test.go b/android/util_test.go index 0e28b568b..20161e52d 100644 --- a/android/util_test.go +++ b/android/util_test.go @@ -20,6 +20,7 @@ import ( "strconv" "strings" "testing" + "unsafe" ) var firstUniqueStringsTestCases = []struct { @@ -754,3 +755,65 @@ func TestSortedUniqueStringValues(t *testing.T) { }) } } + +var reverseTestCases = []struct { + name string + in []string + expected []string +}{ + { + name: "nil", + in: nil, + expected: nil, + }, + { + name: "empty", + in: []string{}, + expected: []string{}, + }, + { + name: "one", + in: []string{"one"}, + expected: []string{"one"}, + }, + { + name: "even", + in: []string{"one", "two"}, + expected: []string{"two", "one"}, + }, + { + name: "odd", + in: []string{"one", "two", "three"}, + expected: []string{"three", "two", "one"}, + }, +} + +func TestReverseSliceInPlace(t *testing.T) { + for _, testCase := range reverseTestCases { + t.Run(testCase.name, func(t *testing.T) { + slice := CopyOf(testCase.in) + slice2 := slice + ReverseSliceInPlace(slice) + if !reflect.DeepEqual(slice, testCase.expected) { + t.Errorf("expected %#v, got %#v", testCase.expected, slice) + } + if unsafe.SliceData(slice) != unsafe.SliceData(slice2) { + t.Errorf("expected slices to share backing array") + } + }) + } +} + +func TestReverseSlice(t *testing.T) { + for _, testCase := range reverseTestCases { + t.Run(testCase.name, func(t *testing.T) { + slice := ReverseSlice(testCase.in) + if !reflect.DeepEqual(slice, testCase.expected) { + t.Errorf("expected %#v, got %#v", testCase.expected, slice) + } + if slice != nil && unsafe.SliceData(testCase.in) == unsafe.SliceData(slice) { + t.Errorf("expected slices to have different backing arrays") + } + }) + } +} diff --git a/android/variable.go b/android/variable.go index 3bec854ea..ca9a221b1 100644 --- a/android/variable.go +++ b/android/variable.go @@ -138,6 +138,7 @@ type variableProperties struct { Srcs []string Exclude_srcs []string + Cmd *string } // eng is true for -eng builds, and can be used to turn on additional heavyweight debugging @@ -156,10 +157,6 @@ type variableProperties struct { } } - Pdk struct { - Enabled *bool `android:"arch_variant"` - } `android:"arch_variant"` - Uml struct { Cppflags []string } @@ -180,12 +177,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"` @@ -220,6 +224,7 @@ type productVariables struct { DeviceCurrentApiLevelForVendorModules *string `json:",omitempty"` DeviceSystemSdkVersions []string `json:",omitempty"` DeviceMaxPageSizeSupported *string `json:",omitempty"` + DevicePageSizeAgnostic *bool `json:",omitempty"` RecoverySnapshotVersion *string `json:",omitempty"` @@ -401,9 +406,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 +462,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 +482,10 @@ type productVariables struct { ReleaseVersion string `json:",omitempty"` ReleaseAconfigValueSets []string `json:",omitempty"` + + ReleaseAconfigFlagDefaultPermission string `json:",omitempty"` + + KeepVndk *bool `json:",omitempty"` } func boolPtr(v bool) *bool { @@ -488,8 +500,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"), @@ -514,6 +526,7 @@ func (v *productVariables) SetDefaultConfig() { DeviceSecondaryCpuVariant: stringPtr("generic"), DeviceSecondaryAbi: []string{"armeabi-v7a", "armeabi"}, DeviceMaxPageSizeSupported: stringPtr("4096"), + DevicePageSizeAgnostic: boolPtr(false), AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"}, AAPTPreferredConfig: stringPtr("xhdpi"), @@ -665,11 +678,16 @@ func ProductVariableProperties(ctx ArchVariantContext, module Module) ProductCon if moduleBase.variableProperties != nil { productVariablesProperty := proptools.FieldNameForProperty("product_variables") - for /* axis */ _, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) { - for config, props := range configToProps { - variableValues := reflect.ValueOf(props).Elem().FieldByName(productVariablesProperty) - productConfigProperties.AddProductConfigProperties(variableValues, config) + if moduleBase.ArchSpecific() { + for /* axis */ _, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) { + for config, props := range configToProps { + variableValues := reflect.ValueOf(props).Elem().FieldByName(productVariablesProperty) + productConfigProperties.AddProductConfigProperties(variableValues, config) + } } + } else { + variableValues := reflect.ValueOf(moduleBase.variableProperties).Elem().FieldByName(productVariablesProperty) + productConfigProperties.AddProductConfigProperties(variableValues, "") } } @@ -725,7 +743,9 @@ func (p *ProductConfigProperties) AddEitherProperty( dst = append(dst, src...) (*p)[propertyName][key] = dst default: - panic(fmt.Errorf("TODO: handle merging value %#v", existing)) + if existing != propertyValue { + panic(fmt.Errorf("TODO: handle merging value %#v", existing)) + } } } else { (*p)[propertyName][key] = propertyValue @@ -938,7 +958,7 @@ func (productConfigProperties *ProductConfigProperties) AddSoongConfigProperties productConfigProperties.AddSoongConfigProperty(propertyName, namespace, soongConfigVariableName, soongConfigVariableValue, os.Name, property.Interface()) } } - } else { + } else if !archOrOsSpecificStruct.IsZero() { // One problem with supporting additional fields is that if multiple branches of // "target" overlap, we don't want them to be in the same select statement (aka // configuration axis). "android" and "host" are disjoint, so it's ok that we only diff --git a/android_sdk/sdk_repo_host.go b/android_sdk/sdk_repo_host.go index 9623a8bc4..7212a0740 100644 --- a/android_sdk/sdk_repo_host.go +++ b/android_sdk/sdk_repo_host.go @@ -166,7 +166,7 @@ func (s *sdkRepoHost) GenerateAndroidBuildActions(ctx android.ModuleContext) { } } else { llvmStrip := config.ClangPath(ctx, "bin/llvm-strip") - llvmLib := config.ClangPath(ctx, "lib/x86_64-unknown-linux-gnu/libc++.so.1") + llvmLib := config.ClangPath(ctx, "lib/x86_64-unknown-linux-gnu/libc++.so") for _, strip := range s.properties.Strip_files { cmd := builder.Command().Tool(llvmStrip).ImplicitTool(llvmLib) if !ctx.Windows() { diff --git a/apex/apex.go b/apex/apex.go index 1d094eb31..8c21d3d7c 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") @@ -1685,6 +1685,7 @@ func apexFileForRustExecutable(ctx android.BaseModuleContext, rustm *rust.Module if rustm.Target().NativeBridge == android.NativeBridgeEnabled { dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath) } + dirInApex = filepath.Join(dirInApex, rustm.RelativeInstallPath()) fileToCopy := android.OutputFileForModule(ctx, rustm, "") androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName af := newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeExecutable, rustm) @@ -1704,6 +1705,7 @@ func apexFileForRustLibrary(ctx android.BaseModuleContext, rustm *rust.Module) a if rustm.Target().NativeBridge == android.NativeBridgeEnabled { dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath) } + dirInApex = filepath.Join(dirInApex, rustm.RelativeInstallPath()) fileToCopy := android.OutputFileForModule(ctx, rustm, "") androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, rustm) @@ -2394,7 +2396,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 +3279,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 +3290,6 @@ func makeApexAvailableBaseline() map[string][]string { "libprocinfo", "libpropertyinfoparser", "libscudo", - "libstdc++", "libsystemproperties", "libtombstoned_client_static", "libunwindstack", @@ -3742,3 +3718,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..da059eb0a 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -390,7 +390,7 @@ func TestBasicApex(t *testing.T) { name: "foo.rust", srcs: ["foo.rs"], rlibs: ["libfoo.rlib.rust"], - dylibs: ["libfoo.dylib.rust"], + rustlibs: ["libfoo.dylib.rust"], apex_available: ["myapex"], } @@ -2794,7 +2794,7 @@ func TestFilesInSubDir(t *testing.T) { name: "myapex", key: "myapex.key", native_shared_libs: ["mylib"], - binaries: ["mybin"], + binaries: ["mybin", "mybin.rust"], prebuilts: ["myetc"], compile_multilib: "both", updatable: false, @@ -2829,6 +2829,13 @@ func TestFilesInSubDir(t *testing.T) { stl: "none", apex_available: [ "myapex" ], } + + rust_binary { + name: "mybin.rust", + srcs: ["foo.rs"], + relative_install_path: "rust_subdir", + apex_available: [ "myapex" ], + } `) generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("generateFsConfig") @@ -2847,6 +2854,7 @@ func TestFilesInSubDir(t *testing.T) { ensureContains(t, cmd, "/bin ") ensureContains(t, cmd, "/bin/foo ") ensureContains(t, cmd, "/bin/foo/bar ") + ensureContains(t, cmd, "/bin/rust_subdir ") } func TestFilesInSubDirWhenNativeBridgeEnabled(t *testing.T) { @@ -3029,7 +3037,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" @@ -3858,6 +3870,7 @@ func TestVndkApexCurrent(t *testing.T) { } `+vndkLibrariesTxtFiles("current"), android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.DeviceVndkVersion = proptools.StringPtr(tc.vndkVersion) + variables.KeepVndk = proptools.BoolPtr(true) })) ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", tc.expectedFiles) }) @@ -5587,6 +5600,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 +5678,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 +5773,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 +5810,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 +5835,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { name: "libfoo", srcs: ["foo/bar/MyClass.java"], apex_available: ["myapex"], + installable: true, } java_sdk_library_import { @@ -5815,6 +5854,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 +5867,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 +5876,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 +5886,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 +5933,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 +5951,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { unsafe_ignore_missing_latest_api: true, apex_available: ["myapex"], permitted_packages: ["bar"], + compile_dex: true, } ` @@ -5910,8 +5962,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 +5974,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 +5983,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 +6022,6 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { java_import { name: "libfoo", - prefer: true, jars: ["libfoo.jar"], apex_available: ["myapex"], permitted_packages: ["foo"], @@ -5967,13 +6029,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 +6047,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 +6064,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 `) }) } @@ -6737,6 +6803,10 @@ func TestApexAvailable_ApexAvailableNameWithVersionCode(t *testing.T) { public_key: "testkey.avbpubkey", private_key: "testkey.pem", } + override_apex { + name: "myoverrideapex", + base: "bar", + } `) fooManifestRule := result.ModuleForTests("foo", "android_common_foo_image").Rule("apexManifestRule") @@ -6753,6 +6823,12 @@ func TestApexAvailable_ApexAvailableNameWithVersionCode(t *testing.T) { if barActualDefaultVersion != barExpectedDefaultVersion { t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion) } + + overrideBarManifestRule := result.ModuleForTests("bar", "android_common_myoverrideapex_bar_image").Rule("apexManifestRule") + overrideBarActualDefaultVersion := overrideBarManifestRule.Args["default_version"] + if overrideBarActualDefaultVersion != barExpectedDefaultVersion { + t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion) + } } func TestApexAvailable_ApexAvailableName(t *testing.T) { @@ -8163,126 +8239,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 +8262,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 +8277,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 +8593,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 +10576,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/apex/vndk.go b/apex/vndk.go index 095e89db3..889324090 100644 --- a/apex/vndk.go +++ b/apex/vndk.go @@ -103,7 +103,7 @@ func apexVndkDepsMutator(mctx android.BottomUpMutatorContext) { } } else if a, ok := mctx.Module().(*apexBundle); ok && a.vndkApex { vndkVersion := proptools.StringDefault(a.vndkProperties.Vndk_version, "current") - mctx.AddDependency(mctx.Module(), prebuiltTag, cc.VndkLibrariesTxtModules(vndkVersion)...) + mctx.AddDependency(mctx.Module(), prebuiltTag, cc.VndkLibrariesTxtModules(vndkVersion, mctx)...) } } diff --git a/apex/vndk_test.go b/apex/vndk_test.go index 21526c3eb..4327a61f8 100644 --- a/apex/vndk_test.go +++ b/apex/vndk_test.go @@ -51,6 +51,7 @@ func TestVndkApexForVndkLite(t *testing.T) { `+vndkLibrariesTxtFiles("current"), android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.DeviceVndkVersion = proptools.StringPtr("") + variables.KeepVndk = proptools.BoolPtr(true) }), ) // VNDK-Lite contains only core variants of VNDK-Sp libraries diff --git a/bazel/aquery.go b/bazel/aquery.go index 95e52ae73..d77d59acf 100644 --- a/bazel/aquery.go +++ b/bazel/aquery.go @@ -17,15 +17,15 @@ package bazel import ( "crypto/sha256" "encoding/base64" + "encoding/json" "fmt" "path/filepath" + analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2" "reflect" "sort" "strings" "sync" - analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2" - "github.com/google/blueprint/metrics" "github.com/google/blueprint/proptools" "google.golang.org/protobuf/proto" @@ -116,6 +116,13 @@ 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 list of files to add as implicit deps to the outputs of this BuildStatement. + // Unlike most properties in BuildStatement, these paths must be relative to the root of + // the whole out/ folder, instead of relative to ctx.Config().BazelContext.OutputBase() + ImplicitDeps []string } // A helper type for aquery processing which facilitates retrieval of path IDs from their @@ -456,7 +463,7 @@ func (a *aqueryArtifactHandler) depsetContentHashes(inputDepsetIds []uint32) ([] // escapes the args received from aquery and creates a command string func commandString(actionEntry *analysis_v2_proto.Action) string { switch actionEntry.Mnemonic { - case "GoCompilePkg": + case "GoCompilePkg", "GoStdlib": argsEscaped := []string{} for _, arg := range actionEntry.Arguments { if arg == "" { @@ -496,6 +503,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 } @@ -572,6 +585,72 @@ func (a *aqueryArtifactHandler) symlinkTreeActionBuildStatement(actionEntry *ana }, nil } +type bazelSandwichJson struct { + Target string `json:"target"` + DependOnTarget *bool `json:"depend_on_target,omitempty"` + ImplicitDeps []string `json:"implicit_deps"` +} + +func (a *aqueryArtifactHandler) unresolvedSymlinkActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) { + outputPaths, depfile, err := a.getOutputPaths(actionEntry) + if err != nil { + return nil, err + } + if len(actionEntry.InputDepSetIds) != 0 || len(outputPaths) != 1 { + return nil, fmt.Errorf("expected 0 inputs and 1 output to symlink action, got: input %q, output %q", actionEntry.InputDepSetIds, outputPaths) + } + target := actionEntry.UnresolvedSymlinkTarget + if target == "" { + return nil, fmt.Errorf("expected an unresolved_symlink_target, but didn't get one") + } + if filepath.Clean(target) != target { + return nil, fmt.Errorf("expected %q, got %q", filepath.Clean(target), target) + } + if strings.HasPrefix(target, "/") { + return nil, fmt.Errorf("no absolute symlinks allowed: %s", target) + } + + out := outputPaths[0] + outDir := filepath.Dir(out) + var implicitDeps []string + if strings.HasPrefix(target, "bazel_sandwich:") { + j := bazelSandwichJson{} + err := json.Unmarshal([]byte(target[len("bazel_sandwich:"):]), &j) + if err != nil { + return nil, err + } + if proptools.BoolDefault(j.DependOnTarget, true) { + implicitDeps = append(implicitDeps, j.Target) + } + implicitDeps = append(implicitDeps, j.ImplicitDeps...) + dotDotsToReachCwd := "" + if outDir != "." { + dotDotsToReachCwd = strings.Repeat("../", strings.Count(outDir, "/")+1) + } + target = proptools.ShellEscapeIncludingSpaces(j.Target) + target = "{DOTDOTS_TO_OUTPUT_ROOT}" + dotDotsToReachCwd + target + } else { + target = proptools.ShellEscapeIncludingSpaces(target) + } + + outDir = proptools.ShellEscapeIncludingSpaces(outDir) + out = proptools.ShellEscapeIncludingSpaces(out) + // Use absolute paths, because some soong actions don't play well with relative paths (for example, `cp -d`). + command := fmt.Sprintf("mkdir -p %[1]s && rm -f %[2]s && ln -sf %[3]s %[2]s", outDir, out, target) + symlinkPaths := outputPaths[:] + + buildStatement := &BuildStatement{ + Command: command, + Depfile: depfile, + OutputPaths: outputPaths, + Env: actionEntry.EnvironmentVariables, + Mnemonic: actionEntry.Mnemonic, + SymlinkPaths: symlinkPaths, + ImplicitDeps: implicitDeps, + } + return buildStatement, nil +} + func (a *aqueryArtifactHandler) symlinkActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) { outputPaths, depfile, err := a.getOutputPaths(actionEntry) if err != nil { @@ -677,10 +756,12 @@ func (a *aqueryArtifactHandler) actionToBuildStatement(actionEntry *analysis_v2_ if len(actionEntry.Arguments) < 1 { return a.templateExpandActionBuildStatement(actionEntry) } - case "FileWrite", "SourceSymlinkManifest": + case "FileWrite", "SourceSymlinkManifest", "RepoMappingManifest": return a.fileWriteActionBuildStatement(actionEntry) case "SymlinkTree": return a.symlinkTreeActionBuildStatement(actionEntry) + case "UnresolvedSymlink": + return a.unresolvedSymlinkActionBuildStatement(actionEntry) } if len(actionEntry.Arguments) < 1 { diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go index 19a584f23..32c87a0a6 100644 --- a/bazel/aquery_test.go +++ b/bazel/aquery_test.go @@ -357,9 +357,11 @@ func TestDepfiles(t *testing.T) { actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{}) if err != nil { t.Errorf("Unexpected error %q", err) + return } if expected := 1; len(actual) != expected { t.Fatalf("Expected %d build statements, got %d", expected, len(actual)) + return } bs := actual[0] @@ -544,6 +546,7 @@ func TestSymlinkTree(t *testing.T) { actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{}) if err != nil { t.Errorf("Unexpected error %q", err) + return } assertBuildStatements(t, []*BuildStatement{ &BuildStatement{ @@ -756,9 +759,11 @@ func TestMiddlemenAction(t *testing.T) { actualBuildStatements, actualDepsets, err := AqueryBuildStatements(data, &metrics.EventHandler{}) if err != nil { t.Errorf("Unexpected error %q", err) + return } if expected := 2; len(actualBuildStatements) != expected { t.Fatalf("Expected %d build statements, got %d %#v", expected, len(actualBuildStatements), actualBuildStatements) + return } expectedDepsetFiles := [][]string{ @@ -859,6 +864,7 @@ func TestSimpleSymlink(t *testing.T) { if err != nil { t.Errorf("Unexpected error %q", err) + return } expectedBuildStatements := []*BuildStatement{ @@ -907,6 +913,7 @@ func TestSymlinkQuotesPaths(t *testing.T) { actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{}) if err != nil { t.Errorf("Unexpected error %q", err) + return } expectedBuildStatements := []*BuildStatement{ @@ -1017,6 +1024,7 @@ func TestTemplateExpandActionSubstitutions(t *testing.T) { actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{}) if err != nil { t.Errorf("Unexpected error %q", err) + return } expectedBuildStatements := []*BuildStatement{ @@ -1088,6 +1096,7 @@ func TestFileWrite(t *testing.T) { actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{}) if err != nil { t.Errorf("Unexpected error %q", err) + return } assertBuildStatements(t, []*BuildStatement{ &BuildStatement{ @@ -1126,6 +1135,7 @@ func TestSourceSymlinkManifest(t *testing.T) { actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{}) if err != nil { t.Errorf("Unexpected error %q", err) + return } assertBuildStatements(t, []*BuildStatement{ &BuildStatement{ @@ -1136,6 +1146,126 @@ func TestSourceSymlinkManifest(t *testing.T) { }, actual) } +func TestUnresolvedSymlink(t *testing.T) { + const inputString = ` +{ + "artifacts": [ + { "id": 1, "path_fragment_id": 1 } + ], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "UnresolvedSymlink", + "configuration_id": 1, + "output_ids": [1], + "primary_output_id": 1, + "execution_platform": "//build/bazel/platforms:linux_x86_64", + "unresolved_symlink_target": "symlink/target" + }], + "path_fragments": [ + { "id": 1, "label": "path/to/symlink" } + ] +} +` + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{}) + if err != nil { + t.Errorf("Unexpected error %q", err) + return + } + assertBuildStatements(t, []*BuildStatement{{ + Command: "mkdir -p path/to && rm -f path/to/symlink && ln -sf symlink/target path/to/symlink", + OutputPaths: []string{"path/to/symlink"}, + Mnemonic: "UnresolvedSymlink", + SymlinkPaths: []string{"path/to/symlink"}, + }}, actual) +} + +func TestUnresolvedSymlinkBazelSandwich(t *testing.T) { + const inputString = ` +{ + "artifacts": [ + { "id": 1, "path_fragment_id": 1 } + ], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "UnresolvedSymlink", + "configuration_id": 1, + "output_ids": [1], + "primary_output_id": 1, + "execution_platform": "//build/bazel/platforms:linux_x86_64", + "unresolved_symlink_target": "bazel_sandwich:{\"target\":\"target/product/emulator_x86_64/system\"}" + }], + "path_fragments": [ + { "id": 1, "label": "path/to/symlink" } + ] +} +` + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{}) + if err != nil { + t.Errorf("Unexpected error %q", err) + return + } + assertBuildStatements(t, []*BuildStatement{{ + Command: "mkdir -p path/to && rm -f path/to/symlink && ln -sf {DOTDOTS_TO_OUTPUT_ROOT}../../target/product/emulator_x86_64/system path/to/symlink", + OutputPaths: []string{"path/to/symlink"}, + Mnemonic: "UnresolvedSymlink", + SymlinkPaths: []string{"path/to/symlink"}, + ImplicitDeps: []string{"target/product/emulator_x86_64/system"}, + }}, actual) +} + +func TestUnresolvedSymlinkBazelSandwichWithAlternativeDeps(t *testing.T) { + const inputString = ` +{ + "artifacts": [ + { "id": 1, "path_fragment_id": 1 } + ], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "UnresolvedSymlink", + "configuration_id": 1, + "output_ids": [1], + "primary_output_id": 1, + "execution_platform": "//build/bazel/platforms:linux_x86_64", + "unresolved_symlink_target": "bazel_sandwich:{\"depend_on_target\":false,\"implicit_deps\":[\"target/product/emulator_x86_64/obj/PACKAGING/systemimage_intermediates/staging_dir.stamp\"],\"target\":\"target/product/emulator_x86_64/system\"}" + }], + "path_fragments": [ + { "id": 1, "label": "path/to/symlink" } + ] +} +` + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{}) + if err != nil { + t.Errorf("Unexpected error %q", err) + return + } + assertBuildStatements(t, []*BuildStatement{{ + Command: "mkdir -p path/to && rm -f path/to/symlink && ln -sf {DOTDOTS_TO_OUTPUT_ROOT}../../target/product/emulator_x86_64/system path/to/symlink", + OutputPaths: []string{"path/to/symlink"}, + Mnemonic: "UnresolvedSymlink", + SymlinkPaths: []string{"path/to/symlink"}, + // Note that the target of the symlink, target/product/emulator_x86_64/system, is not listed here + ImplicitDeps: []string{"target/product/emulator_x86_64/obj/PACKAGING/systemimage_intermediates/staging_dir.stamp"}, + }}, actual) +} + func assertError(t *testing.T, err error, expected string) { t.Helper() if err == nil { @@ -1201,6 +1331,9 @@ func buildStatementEquals(first *BuildStatement, second *BuildStatement) string if !reflect.DeepEqual(sortedStrings(first.SymlinkPaths), sortedStrings(second.SymlinkPaths)) { return "SymlinkPaths" } + if !reflect.DeepEqual(sortedStrings(first.ImplicitDeps), sortedStrings(second.ImplicitDeps)) { + return "ImplicitDeps" + } if first.Depfile != second.Depfile { return "Depfile" } diff --git a/bazel/configurability.go b/bazel/configurability.go index 8f63ec45b..aa58fdc7e 100644 --- a/bazel/configurability.go +++ b/bazel/configurability.go @@ -67,13 +67,17 @@ const ( ConditionsDefaultSelectKey = "//conditions:default" - productVariableBazelPackage = "//build/bazel/product_variables" + productVariableBazelPackage = "//build/bazel/product_config/config_settings" AndroidAndInApex = "android-in_apex" AndroidPlatform = "system" InApex = "in_apex" NonApex = "non_apex" + + ErrorproneDisabled = "errorprone_disabled" + // TODO: b/294868620 - Remove when completing the bug + SanitizersEnabled = "sanitizers_enabled" ) func PowerSetWithoutEmptySet[T any](items []T) [][]T { @@ -216,6 +220,17 @@ 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, + } + + // TODO: b/294868620 - Remove when completing the bug + sanitizersEnabledMap = map[string]string{ + SanitizersEnabled: "//build/bazel/rules/cc:sanitizers_enabled", + ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, + } ) // basic configuration types @@ -229,6 +244,9 @@ const ( productVariables osAndInApex inApex + errorProneDisabled + // TODO: b/294868620 - Remove when completing the bug + sanitizersEnabled ) func osArchString(os string, arch string) string { @@ -237,13 +255,16 @@ 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", + // TODO: b/294868620 - Remove when completing the bug + sanitizersEnabled: "sanitizers_enabled", }[ct] } @@ -274,6 +295,15 @@ 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)) + } + // TODO: b/294868620 - Remove when completing the bug + case sanitizersEnabled: + if _, ok := sanitizersEnabledMap[config]; !ok { + panic(fmt.Errorf("Unknown sanitizers_enabled config: %s", config)) + } default: panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct)) } @@ -303,6 +333,11 @@ func (ca ConfigurationAxis) SelectKey(config string) string { return config case inApex: return inApexMap[config] + case errorProneDisabled: + return errorProneMap[config] + // TODO: b/294868620 - Remove when completing the bug + case sanitizersEnabled: + return sanitizersEnabledMap[config] default: panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType)) } @@ -321,6 +356,11 @@ var ( OsAndInApexAxis = ConfigurationAxis{configurationType: osAndInApex} // An axis for in_apex-specific configurations InApexAxis = ConfigurationAxis{configurationType: inApex} + + ErrorProneAxis = ConfigurationAxis{configurationType: errorProneDisabled} + + // TODO: b/294868620 - Remove when completing the bug + SanitizersEnabledAxis = ConfigurationAxis{configurationType: sanitizersEnabled} ) // ProductVariableConfigurationAxis returns an axis for the given product variable diff --git a/bazel/properties.go b/bazel/properties.go index e22f4dbe7..9c63bc04b 100644 --- a/bazel/properties.go +++ b/bazel/properties.go @@ -194,14 +194,7 @@ func (ll *LabelList) Partition(predicate func(label Label) bool) (LabelList, Lab // UniqueSortedBazelLabels takes a []Label and deduplicates the labels, and returns // the slice in a sorted order. func UniqueSortedBazelLabels(originalLabels []Label) []Label { - uniqueLabelsSet := make(map[Label]bool) - for _, l := range originalLabels { - uniqueLabelsSet[l] = true - } - var uniqueLabels []Label - for l, _ := range uniqueLabelsSet { - uniqueLabels = append(uniqueLabels, l) - } + uniqueLabels := FirstUniqueBazelLabels(originalLabels) sort.SliceStable(uniqueLabels, func(i, j int) bool { return uniqueLabels[i].Label < uniqueLabels[j].Label }) @@ -210,13 +203,13 @@ func UniqueSortedBazelLabels(originalLabels []Label) []Label { func FirstUniqueBazelLabels(originalLabels []Label) []Label { var labels []Label - found := make(map[Label]bool, len(originalLabels)) + found := make(map[string]bool, len(originalLabels)) for _, l := range originalLabels { - if _, ok := found[l]; ok { + if _, ok := found[l.Label]; ok { continue } labels = append(labels, l) - found[l] = true + found[l.Label] = true } return labels } @@ -288,6 +281,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 } @@ -398,7 +426,7 @@ func (la *LabelAttribute) SetSelectValue(axis ConfigurationAxis, config string, switch axis.configurationType { case noConfig: la.Value = &value - case arch, os, osArch, productVariables, osAndInApex: + case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled: if la.ConfigurableValues == nil { la.ConfigurableValues = make(configurableLabels) } @@ -414,7 +442,7 @@ func (la *LabelAttribute) SelectValue(axis ConfigurationAxis, config string) *La switch axis.configurationType { case noConfig: return la.Value - case arch, os, osArch, productVariables, osAndInApex: + case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled: return la.ConfigurableValues[axis][config] default: panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis)) @@ -484,7 +512,7 @@ func (ba *BoolAttribute) SetSelectValue(axis ConfigurationAxis, config string, v switch axis.configurationType { case noConfig: ba.Value = value - case arch, os, osArch, productVariables, osAndInApex: + case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled: if ba.ConfigurableValues == nil { ba.ConfigurableValues = make(configurableBools) } @@ -631,7 +659,7 @@ func (ba BoolAttribute) SelectValue(axis ConfigurationAxis, config string) *bool switch axis.configurationType { case noConfig: return ba.Value - case arch, os, osArch, productVariables, osAndInApex: + case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled: if v, ok := ba.ConfigurableValues[axis][config]; ok { return &v } else { @@ -766,7 +794,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, sanitizersEnabled: if lla.ConfigurableValues == nil { lla.ConfigurableValues = make(configurableLabelLists) } @@ -782,7 +810,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, sanitizersEnabled: return lla.ConfigurableValues[axis][config] default: panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis)) @@ -1140,7 +1168,7 @@ func (sa *StringAttribute) SetSelectValue(axis ConfigurationAxis, config string, switch axis.configurationType { case noConfig: sa.Value = str - case arch, os, osArch, productVariables: + case arch, os, osArch, productVariables, sanitizersEnabled: if sa.ConfigurableValues == nil { sa.ConfigurableValues = make(configurableStrings) } @@ -1156,7 +1184,7 @@ func (sa *StringAttribute) SelectValue(axis ConfigurationAxis, config string) *s switch axis.configurationType { case noConfig: return sa.Value - case arch, os, osArch, productVariables: + case arch, os, osArch, productVariables, sanitizersEnabled: if v, ok := sa.ConfigurableValues[axis][config]; ok { return v } else { @@ -1346,7 +1374,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, sanitizersEnabled: if sla.ConfigurableValues == nil { sla.ConfigurableValues = make(configurableStringLists) } @@ -1362,7 +1390,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, sanitizersEnabled: 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..751cb8b30 100644 --- a/bazel/properties_test.go +++ b/bazel/properties_test.go @@ -33,8 +33,12 @@ func TestUniqueBazelLabels(t *testing.T) { {Label: "b"}, {Label: "a"}, {Label: "c"}, + // namespaces + {Label: "//foo:bar", OriginalModuleName: "bar"}, // when referenced from foo namespace + {Label: "//foo:bar", OriginalModuleName: "//foo:bar"}, // when reference from root namespace }, expectedUniqueLabels: []Label{ + {Label: "//foo:bar", OriginalModuleName: "bar"}, {Label: "a"}, {Label: "b"}, {Label: "c"}, @@ -125,6 +129,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 @@ -137,6 +198,9 @@ func TestFirstUniqueBazelLabelList(t *testing.T) { {Label: "b"}, {Label: "a"}, {Label: "c"}, + // namespaces + {Label: "//foo:bar", OriginalModuleName: "bar"}, // when referenced from foo namespace + {Label: "//foo:bar", OriginalModuleName: "//foo:bar"}, // when referenced from root namespace }, Excludes: []Label{ {Label: "x"}, @@ -150,6 +214,7 @@ func TestFirstUniqueBazelLabelList(t *testing.T) { {Label: "a"}, {Label: "b"}, {Label: "c"}, + {Label: "//foo:bar", OriginalModuleName: "bar"}, }, Excludes: []Label{ {Label: "x"}, @@ -167,6 +232,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..8ed94b498 100644 --- a/bp2build/android_app_conversion_test.go +++ b/bp2build/android_app_conversion_test.go @@ -40,6 +40,7 @@ func TestMinimalAndroidApp(t *testing.T) { "app.java": "", "res/res.png": "", "AndroidManifest.xml": "", + "assets/asset.png": "", }, Blueprint: ` android_app { @@ -54,6 +55,8 @@ android_app { "manifest": `"AndroidManifest.xml"`, "resource_files": `["res/res.png"]`, "sdk_version": `"current"`, + "assets": `["assets/asset.png"]`, + "assets_dir": `"assets"`, }), }}) } @@ -68,6 +71,7 @@ func TestAndroidAppAllSupportedFields(t *testing.T) { "resa/res.png": "", "resb/res.png": "", "manifest/AndroidManifest.xml": "", + "assets_/asset.png": "", }, Blueprint: simpleModuleDoNotConvertBp2build("android_app", "static_lib_dep") + ` android_app { @@ -81,6 +85,7 @@ android_app { java_version: "7", certificate: "foocert", required: ["static_lib_dep"], + asset_dirs: ["assets_"], } `, ExpectedBazelTargets: []string{ @@ -91,6 +96,8 @@ android_app { "resa/res.png", "resb/res.png", ]`, + "assets": `["assets_/asset.png"]`, + "assets_dir": `"assets_"`, "custom_package": `"com.google"`, "deps": `[":static_lib_dep"]`, "java_version": `"7"`, @@ -349,7 +356,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 +366,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 +376,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 +403,7 @@ android_app { "resource_files": `[]`, "manifest_values": `{ "minSdkVersion": "30", + "targetSdkVersion": "30", }`, "sdk_version": `"30"`, }), diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go index 84c7ea2e3..238324761 100644 --- a/bp2build/apex_conversion_test.go +++ b/bp2build/apex_conversion_test.go @@ -1555,7 +1555,7 @@ override_apex { "file_contexts": `":foo-file_contexts"`, "manifest": `"apex_manifest.json"`, "min_sdk_version": `select({ - "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": "30", + "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": "30", "//conditions:default": "31", })`, "package_name": `"pkg_name"`, @@ -1564,7 +1564,7 @@ override_apex { "file_contexts": `":foo-file_contexts"`, "manifest": `"apex_manifest.json"`, "min_sdk_version": `select({ - "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": "30", + "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": "30", "//conditions:default": "31", })`, "package_name": `"override_pkg_name"`, diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go index b22cb2861..5f7b382f0 100644 --- a/bp2build/bp2build.go +++ b/bp2build/bp2build.go @@ -15,7 +15,6 @@ package bp2build import ( - "android/soong/starlark_import" "fmt" "os" "path/filepath" @@ -24,6 +23,7 @@ import ( "android/soong/android" "android/soong/bazel" "android/soong/shared" + "android/soong/starlark_import" ) func deleteFilesExcept(ctx *CodegenContext, rootOutputPath android.OutputPath, except []BazelFile) { @@ -67,6 +67,8 @@ func deleteFilesExcept(ctx *CodegenContext, rootOutputPath android.OutputPath, e // writing .bzl files that are equivalent to Android.bp files that are capable // of being built with Bazel. func Codegen(ctx *CodegenContext) *CodegenMetrics { + ctx.Context().BeginEvent("Codegen") + defer ctx.Context().EndEvent("Codegen") // This directory stores BUILD files that could be eventually checked-in. bp2buildDir := android.PathForOutput(ctx, "bp2build") @@ -79,7 +81,16 @@ func Codegen(ctx *CodegenContext) *CodegenMetrics { fmt.Printf("ERROR: Encountered %d error(s): \nERROR: %s", len(errs), strings.Join(errMsgs, "\n")) os.Exit(1) } - bp2buildFiles := CreateBazelFiles(ctx.Config(), nil, res.buildFileToTargets, ctx.mode) + var bp2buildFiles []BazelFile + ctx.Context().EventHandler.Do("CreateBazelFile", func() { + bp2buildFiles = CreateBazelFiles(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 +99,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 +113,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, metrics) 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..e8c2ef7e0 100644 --- a/bp2build/bp2build_product_config.go +++ b/bp2build/bp2build_product_config.go @@ -1,14 +1,23 @@ package bp2build import ( + "android/soong/android" + "android/soong/android/soongconfig" + "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, + metrics CodegenMetrics) ([]BazelFile, []BazelFile, error) { cfg := &ctx.config targetProduct := "unknown" if cfg.HasDeviceProduct() { @@ -25,9 +34,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 +53,29 @@ func CreateProductConfigFiles( "{VARIANT}", targetBuildVariant, "{PRODUCT_FOLDER}", currentProductFolder) - result := []BazelFile{ + platformMappingContent, err := platformMappingContent( + productReplacer.Replace("@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"), + &productVariables, + ctx.Config().Bp2buildSoongConfigDefinitions, + metrics.convertedModulePathMap) + if err != nil { + return nil, nil, err + } + + productsForTestingMap, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing") + if err != nil { + return nil, nil, err + } + productsForTesting := android.SortedKeys(productsForTestingMap) + for i := range productsForTesting { + productsForTesting[i] = fmt.Sprintf(" \"@//build/bazel/tests/products:%s\",", productsForTesting[i]) + } + + injectionDirFiles := []BazelFile{ newFile( currentProductFolder, "soong.variables.bzl", - `variables = json.decode("""`+strings.ReplaceAll(string(bytes), "\\", "\\\\")+`""")`), + `variables = json.decode("""`+strings.ReplaceAll(string(productVariablesBytes), "\\", "\\\\")+`""")`), newFile( currentProductFolder, "BUILD", @@ -80,6 +112,7 @@ load("@//build/bazel/product_config:android_product.bzl", "android_product") android_product( name = "mixed_builds_product-{VARIANT}", soong_variables = _soong_variables, + extra_constraints = ["@//build/bazel/platforms:mixed_builds"], ) `)), newFile( @@ -92,16 +125,17 @@ android_product( # currently lunched product, they should all be listed here product_labels = [ "@soong_injection//product_config_platforms:mixed_builds_product-{VARIANT}", - "@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}" -] -`)), + "@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}", +`)+strings.Join(productsForTesting, "\n")+"\n]\n"), newFile( "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} +build:linux_x86 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86 build:linux_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64 build:linux_bionic_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_bionic_x86_64 build:linux_musl_x86 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86 @@ -120,6 +154,247 @@ 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, + soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions, + convertedModulePathMap map[string]string) (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 + + mergedConvertedModulePathMap := make(map[string]string) + for k, v := range convertedModulePathMap { + mergedConvertedModulePathMap[k] = v + } + additionalModuleNamesToPackages, err := starlark_import.GetStarlarkValue[map[string]string]("additional_module_names_to_packages") + if err != nil { + return "", err + } + for k, v := range additionalModuleNamesToPackages { + mergedConvertedModulePathMap[k] = v + } + + result.WriteString("platforms:\n") + platformMappingSingleProduct(mainProductLabel, mainProductVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result) + for product, productVariablesStarlark := range productsForTesting { + productVariables, err := starlarkMapToProductVariables(productVariablesStarlark) + if err != nil { + return "", err + } + platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &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, + soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions, + convertedModulePathMap map[string]string, + result *strings.Builder) { + targetBuildVariant := "user" + if proptools.Bool(productVariables.Eng) { + targetBuildVariant = "eng" + } else if proptools.Bool(productVariables.Debuggable) { + targetBuildVariant = "userdebug" + } + + platform_sdk_version := -1 + if productVariables.Platform_sdk_version != nil { + platform_sdk_version = *productVariables.Platform_sdk_version + } + + defaultAppCertificateFilegroup := "//build/bazel/utils:empty_filegroup" + if proptools.String(productVariables.DefaultAppCertificate) != "" { + defaultAppCertificateFilegroup = "@//" + filepath.Dir(proptools.String(productVariables.DefaultAppCertificate)) + ":android_certificate_directory" + } + + 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:arc=%t\n", proptools.Bool(productVariables.Arc))) + 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:binder32bit=%t\n", proptools.Bool(productVariables.Binder32bit))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_from_text_stub=%t\n", proptools.Bool(productVariables.Build_from_text_stub))) + 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: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:debuggable=%t\n", proptools.Bool(productVariables.Debuggable))) + 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:default_app_certificate_filegroup=%s\n", defaultAppCertificateFilegroup)) + 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_page_size_agnostic=%t\n", proptools.Bool(productVariables.DevicePageSizeAgnostic))) + 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:enforce_vintf_manifest=%t\n", proptools.Bool(productVariables.Enforce_vintf_manifest))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:eng=%t\n", proptools.Bool(productVariables.Eng))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:malloc_not_svelte=%t\n", proptools.Bool(productVariables.Malloc_not_svelte))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:malloc_pattern_fill_contents=%t\n", proptools.Bool(productVariables.Malloc_pattern_fill_contents))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:malloc_zero_contents=%t\n", proptools.Bool(productVariables.Malloc_zero_contents))) + 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:native_coverage=%t\n", proptools.Bool(productVariables.Native_coverage))) + 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:platform_sdk_version=%d\n", platform_sdk_version)) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:safestack=%t\n", proptools.Bool(productVariables.Safestack))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:target_build_variant=%s\n", targetBuildVariant)) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:treble_linker_namespaces=%t\n", proptools.Bool(productVariables.Treble_linker_namespaces))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:tidy_checks=%s\n", proptools.String(productVariables.TidyChecks))) + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:uml=%t\n", proptools.Bool(productVariables.Uml))) + 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, ","))) + + for _, override := range productVariables.CertificateOverrides { + parts := strings.SplitN(override, ":", 2) + if apexPath, ok := convertedModulePathMap[parts[0]]; ok { + if overrideCertPath, ok := convertedModulePathMap[parts[1]]; ok { + result.WriteString(fmt.Sprintf(" --%s:%s_certificate_override=%s:%s\n", apexPath, parts[0], overrideCertPath, parts[1])) + } + } + } + + for namespace, namespaceContents := range productVariables.VendorVars { + for variable, value := range namespaceContents { + key := namespace + "__" + variable + _, hasBool := soongConfigDefinitions.BoolVars[key] + _, hasString := soongConfigDefinitions.StringVars[key] + _, hasValue := soongConfigDefinitions.ValueVars[key] + if !hasBool && !hasString && !hasValue { + // Not all soong config variables are defined in Android.bp files. For example, + // prebuilt_bootclasspath_fragment uses soong config variables in a nonstandard + // way, that causes them to be present in the soong.variables file but not + // defined in an Android.bp file. There's also nothing stopping you from setting + // a variable in make that doesn't exist in soong. We only generate build + // settings for the ones that exist in soong, so skip all others. + continue + } + if hasBool && hasString || hasBool && hasValue || hasString && hasValue { + panic(fmt.Sprintf("Soong config variable %s:%s appears to be of multiple types. bool? %t, string? %t, value? %t", namespace, variable, hasBool, hasString, hasValue)) + } + if hasBool { + // Logic copied from soongConfig.Bool() + value = strings.ToLower(value) + if value == "1" || value == "y" || value == "yes" || value == "on" || value == "true" { + value = "true" + } else { + value = "false" + } + } + result.WriteString(fmt.Sprintf(" --//build/bazel/product_config/soong_config_variables:%s=%s\n", strings.ToLower(key), value)) + } + } + } +} + +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 == "VendorSnapshotModules" || + name == "RecoverySnapshotModules" { + // These variables have more complicated types, and we don't need them right now + continue + } + if _, ok := in[name]; ok { + if name == "VendorVars" { + vendorVars, err := starlark_import.Unmarshal[map[string]map[string]string](in[name]) + if err != nil { + return result, err + } + field.Set(reflect.ValueOf(vendorVars)) + continue + } + 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()) + } + } + } + + result.Native_coverage = proptools.BoolPtr( + proptools.Bool(result.GcovCoverage) || + proptools.Bool(result.ClangCoverage)) 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..02d83b4d1 --- /dev/null +++ b/bp2build/bp2build_product_config_test.go @@ -0,0 +1,89 @@ +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 + } + testCase.result.Native_coverage = proptools.BoolPtr(false) + 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..cd1bc7f19 100644 --- a/bp2build/build_conversion.go +++ b/bp2build/build_conversion.go @@ -29,7 +29,9 @@ import ( "android/soong/bazel" "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" ) @@ -93,16 +95,16 @@ func (targets BazelTargets) sort() { // statements (use LoadStatements for that), since the targets are usually not // adjacent to the load statements at the top of the BUILD file. func (targets BazelTargets) String() string { - var res string + var res strings.Builder for i, target := range targets { if target.ruleClass != "package" { - res += target.content + res.WriteString(target.content) } if i != len(targets)-1 { - res += "\n\n" + res.WriteString("\n\n") } } - return res + return res.String() } // LoadStatements return the string representation of the sorted and deduplicated @@ -252,7 +254,408 @@ 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 + Data bazel.LabelListAttribute + Target_compatible_with bazel.LabelListAttribute + + // attributes for the dynamically generated go_test target + Embed bazel.LabelListAttribute +} + +type goTestProperties struct { + name string + dir string + testSrcs []string + linuxTestSrcs []string + darwinTestSrcs []string + testData []string + // Name of the target that should be compiled together with the test + embedName string +} + +// Creates a go_test target for bootstrap_go_package / blueprint_go_binary +func generateBazelTargetsGoTest(ctx *android.Context, goModulesMap nameToGoLibraryModule, gp goTestProperties) (BazelTarget, error) { + ca := android.CommonAttributes{ + Name: gp.name, + } + ga := goAttributes{ + Srcs: goSrcLabels(ctx.Config(), gp.dir, gp.testSrcs, gp.linuxTestSrcs, gp.darwinTestSrcs), + Data: goSrcLabels(ctx.Config(), gp.dir, gp.testData, []string{}, []string{}), + Embed: bazel.MakeLabelListAttribute( + bazel.MakeLabelList( + []bazel.Label{bazel.Label{Label: ":" + gp.embedName}}, + ), + ), + Target_compatible_with: targetNotCompatibleWithAndroid(), + } + + libTest := goBazelTarget{ + targetName: gp.name, + targetPackage: gp.dir, + bazelRuleClass: "go_test", + bazelRuleLoadLocation: "@io_bazel_rules_go//go:def.bzl", + bazelAttributes: []interface{}{&ca, &ga}, + } + return generateBazelTarget(ctx, libTest) +} + +// TODO - b/288491147: testSrcs of certain bootstrap_go_package/blueprint_go_binary are not hermetic and depend on +// testdata checked into the filesystem. +// Denylist the generation of go_test targets for these Soong modules. +// The go_library/go_binary will still be generated, since those are hermitic. +var ( + goTestsDenylist = []string{ + "android-archive-zip", + "bazel_notice_gen", + "blueprint-bootstrap-bpdoc", + "blueprint-microfactory", + "blueprint-pathtools", + "bssl_ar", + "compliance_checkmetadata", + "compliance_checkshare", + "compliance_dumpgraph", + "compliance_dumpresolutions", + "compliance_listshare", + "compliance-module", + "compliancenotice_bom", + "compliancenotice_shippedlibs", + "compliance_rtrace", + "compliance_sbom", + "golang-protobuf-internal-fuzz-jsonfuzz", + "golang-protobuf-internal-fuzz-textfuzz", + "golang-protobuf-internal-fuzz-wirefuzz", + "htmlnotice", + "protoc-gen-go", + "rbcrun-module", + "spdx-tools-builder", + "spdx-tools-builder2v1", + "spdx-tools-builder2v2", + "spdx-tools-builder2v3", + "spdx-tools-idsearcher", + "spdx-tools-spdx-json", + "spdx-tools-utils", + "soong-ui-build", + "textnotice", + "xmlnotice", + } +) + +func testOfGoPackageIsIncompatible(g *bootstrap.GoPackage) bool { + return android.InList(g.Name(), goTestsDenylist) || + // Denylist tests of soong_build + // Theses tests have a guard that prevent usage outside a test environment + // The guard (`ensureTestOnly`) looks for a `-test` in os.Args, which is present in soong's gotestrunner, but missing in `b test` + g.IsPluginFor("soong_build") || + // soong-android is a dep of soong_build + // This dependency is created by soong_build by listing it in its deps explicitly in Android.bp, and not via `plugin_for` in `soong-android` + g.Name() == "soong-android" +} + +func testOfGoBinaryIsIncompatible(g *bootstrap.GoBinary) bool { + return android.InList(g.Name(), goTestsDenylist) +} + +func generateBazelTargetsGoPackage(ctx *android.Context, g *bootstrap.GoPackage, goModulesMap nameToGoLibraryModule) ([]BazelTarget, []error) { + 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}, + } + retTargets := []BazelTarget{} + var retErrs []error + if libTarget, err := generateBazelTarget(ctx, lib); err == nil { + retTargets = append(retTargets, libTarget) + } else { + retErrs = []error{err} + } + + // If the library contains test srcs, create an additional go_test target + if !testOfGoPackageIsIncompatible(g) && (len(g.TestSrcs()) > 0 || len(g.LinuxTestSrcs()) > 0 || len(g.DarwinTestSrcs()) > 0) { + gp := goTestProperties{ + name: g.Name() + "-test", + dir: ctx.ModuleDir(g), + testSrcs: g.TestSrcs(), + linuxTestSrcs: g.LinuxTestSrcs(), + darwinTestSrcs: g.DarwinTestSrcs(), + testData: g.TestData(), + embedName: g.Name(), // embed the source go_library in the test so that its .go files are included in the compilation unit + } + if libTestTarget, err := generateBazelTargetsGoTest(ctx, goModulesMap, gp); err == nil { + retTargets = append(retTargets, libTestTarget) + } else { + retErrs = append(retErrs, err) + } + } + + return retTargets, retErrs +} + +type goLibraryModule struct { + 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(), + } + + retTargets := []BazelTarget{} + var retErrs []error + + // For this bootstrap_go_package dep chain, + // A --> B --> C ( ---> depends on) + // Soong provides the convenience of only listing B as deps of A even if a src file of A imports C + // 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) + + goSource := "" + // If the library contains test srcs, create an additional go_test target + // The go_test target will embed a go_source containining the source .go files it tests + if !testOfGoBinaryIsIncompatible(g) && (len(g.TestSrcs()) > 0 || len(g.LinuxTestSrcs()) > 0 || len(g.DarwinTestSrcs()) > 0) { + // Create a go_source containing the source .go files of go_library + // This target will be an `embed` of the go_binary and go_test + goSource = g.Name() + "-source" + ca := android.CommonAttributes{ + Name: goSource, + } + ga := goAttributes{ + Srcs: goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs()), + Deps: goDepLabels(transitiveDeps, goModulesMap), + Target_compatible_with: targetNotCompatibleWithAndroid(), + } + libTestSource := goBazelTarget{ + targetName: goSource, + targetPackage: ctx.ModuleDir(g), + bazelRuleClass: "go_source", + bazelRuleLoadLocation: "@io_bazel_rules_go//go:def.bzl", + bazelAttributes: []interface{}{&ca, &ga}, + } + if libSourceTarget, err := generateBazelTarget(ctx, libTestSource); err == nil { + retTargets = append(retTargets, libSourceTarget) + } else { + retErrs = append(retErrs, err) + } + + // Create a go_test target + gp := goTestProperties{ + name: g.Name() + "-test", + dir: ctx.ModuleDir(g), + testSrcs: g.TestSrcs(), + linuxTestSrcs: g.LinuxTestSrcs(), + darwinTestSrcs: g.DarwinTestSrcs(), + testData: g.TestData(), + // embed the go_source in the test + embedName: g.Name() + "-source", + } + if libTestTarget, err := generateBazelTargetsGoTest(ctx, goModulesMap, gp); err == nil { + retTargets = append(retTargets, libTestTarget) + } else { + retErrs = append(retErrs, err) + } + + } + + // Create a go_binary target + ga := goAttributes{ + Deps: goDepLabels(transitiveDeps, goModulesMap), + Target_compatible_with: targetNotCompatibleWithAndroid(), + } + + // If the binary has testSrcs, embed the common `go_source` + if goSource != "" { + ga.Embed = bazel.MakeLabelListAttribute( + bazel.MakeLabelList( + []bazel.Label{bazel.Label{Label: ":" + goSource}}, + ), + ) + } else { + ga.Srcs = goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs()) + } + + bin := goBazelTarget{ + targetName: g.Name(), + targetPackage: ctx.ModuleDir(g), + bazelRuleClass: "go_binary", + bazelRuleLoadLocation: "@io_bazel_rules_go//go:def.bzl", + bazelAttributes: []interface{}{&ca, &ga}, + } + + if binTarget, err := generateBazelTarget(ctx, bin); err == nil { + retTargets = append(retTargets, binTarget) + } else { + retErrs = []error{err} + } + + return retTargets, retErrs +} + func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (conversionResults, []error) { + ctx.Context().BeginEvent("GenerateBazelTargets") + defer ctx.Context().EndEvent("GenerateBazelTargets") buildFileToTargets := make(map[string]BazelTargets) // Simple metrics tracking for bp2build @@ -262,6 +665,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 +676,7 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers dirs[dir] = true var targets []BazelTarget + var targetErrs []error switch ctx.Mode() { case Bp2Build: @@ -278,6 +686,9 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers // // bp2build converters are used for the majority of modules. if b, ok := m.(android.Bazelable); ok && b.HasHandcraftedLabel() { + if aModule, ok := m.(android.Module); ok && aModule.IsConvertedByBp2build() { + panic(fmt.Errorf("module %q [%s] [%s] was both converted with bp2build and has a handcrafted label", bpCtx.ModuleName(m), moduleType, dir)) + } // Handle modules converted to handcrafted targets. // // Since these modules are associated with some handcrafted @@ -317,7 +728,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 +746,16 @@ 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") + metrics.AddConvertedModule(glib, "go_library", dir) + } else if gbin, ok := m.(*bootstrap.GoBinary); ok { + targets, targetErrs = generateBazelTargetsGoBinary(bpCtx, gbin, nameToGoLibMap) + errs = append(errs, targetErrs...) + metrics.IncrementRuleClassCount("go_binary") + metrics.AddConvertedModule(gbin, "go_binary", dir) } else { metrics.AddUnconvertedModule(m, moduleType, dir, android.UnconvertedReason{ ReasonType: int(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED), diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go index e127fd542..8ee0439c0 100644 --- a/bp2build/build_conversion_test.go +++ b/bp2build/build_conversion_test.go @@ -640,7 +640,10 @@ func TestBp2buildHostAndDevice(t *testing.T) { }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{ - "target_compatible_with": `["//build/bazel/product_variables:unbundled_build"]`, + "target_compatible_with": `select({ + "//build/bazel/product_config/config_settings:unbundled_build": [], + "//conditions:default": ["@platforms//:incompatible"], + })`, }), }, }, @@ -1946,3 +1949,46 @@ func TestPrettyPrintSelectMapEqualValues(t *testing.T) { actual, _ := prettyPrintAttribute(lla, 0) android.AssertStringEquals(t, "Print the common value if all keys in an axis have the same value", `[":libfoo.impl"]`, actual) } + +// If CommonAttributes.Dir is set, the bazel target should be created in that dir +func TestCreateBazelTargetInDifferentDir(t *testing.T) { + t.Parallel() + bp := ` + custom { + name: "foo", + dir: "subdir", + } + ` + registerCustomModule := func(ctx android.RegistrationContext) { + ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice) + } + // Check that foo is not created in root dir + RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{ + Description: "foo is not created in root dir because it sets dir explicitly", + Blueprint: bp, + Filesystem: map[string]string{ + "subdir/Android.bp": "", + }, + ExpectedBazelTargets: []string{}, + }) + // Check that foo is created in `subdir` + RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{ + Description: "foo is created in `subdir` because it sets dir explicitly", + Blueprint: bp, + Filesystem: map[string]string{ + "subdir/Android.bp": "", + }, + Dir: "subdir", + ExpectedBazelTargets: []string{ + MakeBazelTarget("custom", "foo", AttrNameToString{}), + }, + }) + // Check that we cannot create target in different dir if it is does not an Android.bp + RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{ + Description: "foo cannot be created in `subdir` because it does not contain an Android.bp file", + Blueprint: bp, + Dir: "subdir", + ExpectedErr: fmt.Errorf("Cannot use ca.Dir to create a BazelTarget in dir: subdir since it does not contain an Android.bp file"), + }) + +} diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go index fa1bf8af6..402d4b013 100644 --- a/bp2build/bzl_conversion_test.go +++ b/bp2build/bzl_conversion_test.go @@ -94,6 +94,7 @@ custom = rule( # bazel_module end "bool_prop": attr.bool(), "bool_ptr_prop": attr.bool(), + "dir": attr.string(), "embedded_prop": attr.string(), "int64_ptr_prop": attr.int(), # nested_props start @@ -126,6 +127,7 @@ custom_defaults = rule( "arch_paths_exclude": attr.string_list(), "bool_prop": attr.bool(), "bool_ptr_prop": attr.bool(), + "dir": attr.string(), "embedded_prop": attr.string(), "int64_ptr_prop": attr.int(), # nested_props start @@ -158,6 +160,7 @@ custom_test_ = rule( "arch_paths_exclude": attr.string_list(), "bool_prop": attr.bool(), "bool_ptr_prop": attr.bool(), + "dir": attr.string(), "embedded_prop": attr.string(), "int64_ptr_prop": attr.int(), # nested_props start @@ -199,7 +202,7 @@ func TestGenerateSoongModuleBzl(t *testing.T) { content: "irrelevant", }, } - files := CreateBazelFiles(android.NullConfig("out", "out/soong"), ruleShims, make(map[string]BazelTargets), QueryView) + files := CreateBazelFiles(ruleShims, make(map[string]BazelTargets), QueryView) var actualSoongModuleBzl BazelFile for _, f := range files { diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go index 18cb9e116..90db36573 100644 --- a/bp2build/cc_binary_conversion_test.go +++ b/bp2build/cc_binary_conversion_test.go @@ -880,8 +880,15 @@ func TestCcBinaryWithSanitizerBlocklist(t *testing.T) { }`, targets: []testBazelTarget{ {"cc_binary", "foo", AttrNameToString{ + "copts": `select({ + "//build/bazel/rules/cc:sanitizers_enabled": ["-fsanitize-ignorelist=$(location foo_blocklist.txt)"], + "//conditions:default": [], + })`, + "additional_compiler_inputs": `select({ + "//build/bazel/rules/cc:sanitizers_enabled": [":foo_blocklist.txt"], + "//conditions:default": [], + })`, "local_includes": `["."]`, - "features": `["ubsan_blocklist_foo_blocklist_txt"]`, }}, }, }) @@ -1214,3 +1221,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..e70cd106f 100644 --- a/bp2build/cc_library_conversion_test.go +++ b/bp2build/cc_library_conversion_test.go @@ -1260,14 +1260,14 @@ cc_library { "//build/bazel/platforms/arch:arm": [], "//conditions:default": [":arm_static_lib_excludes_bp2build_cc_library_static"], }) + select({ - "//build/bazel/product_variables:malloc_not_svelte": [], + "//build/bazel/product_config/config_settings:malloc_not_svelte": [], "//conditions:default": [":malloc_not_svelte_static_lib_excludes_bp2build_cc_library_static"], })`, "implementation_dynamic_deps": `select({ "//build/bazel/platforms/arch:arm": [], "//conditions:default": [":arm_shared_lib_excludes"], }) + select({ - "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_shared_lib"], + "//build/bazel/product_config/config_settings:malloc_not_svelte": [":malloc_not_svelte_shared_lib"], "//conditions:default": [], })`, "srcs_c": `["common.c"]`, @@ -1275,7 +1275,7 @@ cc_library { "//build/bazel/platforms/arch:arm": [], "//conditions:default": [":arm_whole_static_lib_excludes_bp2build_cc_library_static"], }) + select({ - "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_whole_static_lib_bp2build_cc_library_static"], + "//build/bazel/product_config/config_settings:malloc_not_svelte": [":malloc_not_svelte_whole_static_lib_bp2build_cc_library_static"], "//conditions:default": [":malloc_not_svelte_whole_static_lib_excludes_bp2build_cc_library_static"], })`, }), @@ -1307,7 +1307,7 @@ cc_library { `, ExpectedBazelTargets: makeCcLibraryTargets("foo_static", AttrNameToString{ "implementation_deps": `select({ - "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_header_lib"], + "//build/bazel/product_config/config_settings:malloc_not_svelte": [":malloc_not_svelte_header_lib"], "//conditions:default": [], })`, "srcs_c": `["common.c"]`, @@ -2434,12 +2434,18 @@ cc_library { }), MakeBazelTarget("cc_library_shared", "a", AttrNameToString{ "dynamic_deps": `[":libprotobuf-cpp-lite"]`, "whole_archive_deps": `[":a_cc_proto_lite"]`, - }), MakeBazelTargetNoRestrictions("proto_library", "a_fg_proto_bp2build_converted", AttrNameToString{ + }), MakeBazelTargetNoRestrictions("proto_library", "a_fg_proto_proto", AttrNameToString{ "srcs": `["a_fg.proto"]`, "tags": `[ "apex_available=//apex_available:anyapex", "manual", ]`, + }), MakeBazelTargetNoRestrictions("alias", "a_fg_proto_bp2build_converted", AttrNameToString{ + "actual": `"//.:a_fg_proto_proto"`, + "tags": `[ + "apex_available=//apex_available:anyapex", + "manual", + ]`, }), MakeBazelTargetNoRestrictions("filegroup", "a_fg_proto", AttrNameToString{ "srcs": `["a_fg.proto"]`, }), @@ -2476,12 +2482,18 @@ cc_library { }), MakeBazelTarget("cc_library_shared", "a", AttrNameToString{ "dynamic_deps": `[":libprotobuf-cpp-lite"]`, "whole_archive_deps": `[":a_cc_proto_lite"]`, - }), MakeBazelTargetNoRestrictions("proto_library", "a_fg_proto_bp2build_converted", AttrNameToString{ + }), MakeBazelTargetNoRestrictions("proto_library", "a_fg_proto_proto", AttrNameToString{ "srcs": `["a_fg.proto"]`, "tags": `[ "apex_available=//apex_available:anyapex", "manual", ]`, + }), MakeBazelTargetNoRestrictions("alias", "a_fg_proto_bp2build_converted", AttrNameToString{ + "actual": `"//.:a_fg_proto_proto"`, + "tags": `[ + "apex_available=//apex_available:anyapex", + "manual", + ]`, }), MakeBazelTargetNoRestrictions("filegroup", "a_fg_proto", AttrNameToString{ "srcs": `["a_fg.proto"]`, }), @@ -4194,11 +4206,25 @@ cc_library { `, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{ - "features": `["ubsan_blocklist_foo_blocklist_txt"]`, + "copts": `select({ + "//build/bazel/rules/cc:sanitizers_enabled": ["-fsanitize-ignorelist=$(location foo_blocklist.txt)"], + "//conditions:default": [], + })`, + "additional_compiler_inputs": `select({ + "//build/bazel/rules/cc:sanitizers_enabled": [":foo_blocklist.txt"], + "//conditions:default": [], + })`, "local_includes": `["."]`, }), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{ - "features": `["ubsan_blocklist_foo_blocklist_txt"]`, + "copts": `select({ + "//build/bazel/rules/cc:sanitizers_enabled": ["-fsanitize-ignorelist=$(location foo_blocklist.txt)"], + "//conditions:default": [], + })`, + "additional_compiler_inputs": `select({ + "//build/bazel/rules/cc:sanitizers_enabled": [":foo_blocklist.txt"], + "//conditions:default": [], + })`, "local_includes": `["."]`, }), }, @@ -4631,7 +4657,7 @@ func TestCcLibraryCppFlagsInProductVariables(t *testing.T) { "-Wextra", "-DDEBUG_ONLY_CODE=0", ] + select({ - "//build/bazel/product_variables:eng": [ + "//build/bazel/product_config/config_settings:eng": [ "-UDEBUG_ONLY_CODE", "-DDEBUG_ONLY_CODE=1", ], @@ -4903,3 +4929,142 @@ cc_library_shared { }, }) } + +// Bazel enforces that proto_library and the .proto file are in the same bazel package +func TestGenerateProtoLibraryInSamePackage(t *testing.T) { + tc := Bp2buildTestCase{ + Description: "cc_library depends on .proto files from multiple packages", + ModuleTypeUnderTest: "cc_library", + ModuleTypeUnderTestFactory: cc.LibraryFactory, + Blueprint: ` +cc_library_static { + name: "foo", + srcs: [ + "foo.proto", + "bar/bar.proto", // Different package because there is a bar/Android.bp + "baz/subbaz/baz.proto", // Different package because there is baz/subbaz/Android.bp + ], + proto: { + canonical_path_from_root: true, + } +} +` + simpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"), + Filesystem: map[string]string{ + "bar/Android.bp": "", + "baz/subbaz/Android.bp": "", + }, + } + + // We will run the test 3 times and check in the root, bar and baz/subbaz directories + // Root dir + tc.ExpectedBazelTargets = []string{ + MakeBazelTarget("cc_library_static", "foo", AttrNameToString{ + "local_includes": `["."]`, + "deps": `[":libprotobuf-cpp-lite"]`, + "implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`, + }), + MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{ + "srcs": `["foo.proto"]`, + }), + MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{ + "deps": `[ + ":foo_proto", + "//bar:foo_proto", + "//baz/subbaz:foo_proto", + ]`, + }), + } + runCcLibraryTestCase(t, tc) + + // bar dir + tc.Dir = "bar" + tc.ExpectedBazelTargets = []string{ + MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{ + "srcs": `["//bar:bar.proto"]`, + "tags": `["manual"]`, + }), + } + runCcLibraryTestCase(t, tc) + + // baz/subbaz dir + tc.Dir = "baz/subbaz" + tc.ExpectedBazelTargets = []string{ + MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{ + "srcs": `["//baz/subbaz:baz.proto"]`, + "tags": `["manual"]`, + }), + } + runCcLibraryTestCase(t, tc) +} + +// Bazel enforces that proto_library and the .proto file are in the same bazel package +func TestGenerateProtoLibraryInSamePackageNotCanonicalFromRoot(t *testing.T) { + tc := Bp2buildTestCase{ + Description: "cc_library depends on .proto files from multiple packages", + ModuleTypeUnderTest: "cc_library", + ModuleTypeUnderTestFactory: cc.LibraryFactory, + Blueprint: ` +cc_library_static { + name: "foo", + srcs: [ + "foo.proto", + "bar/bar.proto", // Different package because there is a bar/Android.bp + "baz/subbaz/baz.proto", // Different package because there is baz/subbaz/Android.bp + ], + proto: { + canonical_path_from_root: false, + } +} +` + simpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"), + Filesystem: map[string]string{ + "bar/Android.bp": "", + "baz/subbaz/Android.bp": "", + }, + } + + // We will run the test 3 times and check in the root, bar and baz/subbaz directories + // Root dir + tc.ExpectedBazelTargets = []string{ + MakeBazelTarget("cc_library_static", "foo", AttrNameToString{ + "local_includes": `["."]`, + "deps": `[":libprotobuf-cpp-lite"]`, + "implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`, + }), + MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{ + "srcs": `["foo.proto"]`, + "strip_import_prefix": `""`, + }), + MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{ + "deps": `[ + ":foo_proto", + "//bar:foo_proto", + "//baz/subbaz:foo_proto", + ]`, + }), + } + runCcLibraryTestCase(t, tc) + + // bar dir + tc.Dir = "bar" + tc.ExpectedBazelTargets = []string{ + MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{ + "srcs": `["//bar:bar.proto"]`, + "strip_import_prefix": `""`, + "import_prefix": `"bar"`, + "tags": `["manual"]`, + }), + } + runCcLibraryTestCase(t, tc) + + // baz/subbaz dir + tc.Dir = "baz/subbaz" + tc.ExpectedBazelTargets = []string{ + MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{ + "srcs": `["//baz/subbaz:baz.proto"]`, + "strip_import_prefix": `""`, + "import_prefix": `"baz/subbaz"`, + "tags": `["manual"]`, + }), + } + runCcLibraryTestCase(t, tc) +} diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go index 2d61d5355..90b13b03f 100644 --- a/bp2build/cc_library_shared_conversion_test.go +++ b/bp2build/cc_library_shared_conversion_test.go @@ -1225,7 +1225,14 @@ cc_library_shared { `, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{ - "features": `["ubsan_blocklist_foo_blocklist_txt"]`, + "copts": `select({ + "//build/bazel/rules/cc:sanitizers_enabled": ["-fsanitize-ignorelist=$(location foo_blocklist.txt)"], + "//conditions:default": [], + })`, + "additional_compiler_inputs": `select({ + "//build/bazel/rules/cc:sanitizers_enabled": [":foo_blocklist.txt"], + "//conditions:default": [], + })`, "local_includes": `["."]`, }), }, diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go index 18225dfa2..89ec8f9a7 100644 --- a/bp2build/cc_library_static_conversion_test.go +++ b/bp2build/cc_library_static_conversion_test.go @@ -1003,6 +1003,38 @@ cc_library_static { }) } +func TestCcLibraryStaticGeneratedHeadersMultipleExports(t *testing.T) { + runCcLibraryStaticTestCase(t, Bp2buildTestCase{ + Blueprint: soongCcLibraryStaticPreamble + ` +genrule { + name: "generated_hdr", + cmd: "nothing to see here", + export_include_dirs: ["foo", "bar"], + bazel_module: { bp2build_available: false }, +} + +genrule { + name: "export_generated_hdr", + cmd: "nothing to see here", + export_include_dirs: ["a", "b"], + bazel_module: { bp2build_available: false }, +} + +cc_library_static { + name: "foo_static", + generated_headers: ["generated_hdr", "export_generated_hdr"], + export_generated_headers: ["export_generated_hdr"], + include_build_directory: false, +}`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{ + "deps": `[":export_generated_hdr__header_library"]`, + "implementation_deps": `[":generated_hdr__header_library"]`, + }), + }, + }) +} + // generated_headers has "variant_prepend" tag. In bp2build output, // variant info(select) should go before general info. func TestCcLibraryStaticArchSrcsExcludeSrcsGeneratedFiles(t *testing.T) { @@ -1156,13 +1188,13 @@ cc_library_static { ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{ "copts": `select({ - "//build/bazel/product_variables:binder32bit": ["-Wbinder32bit"], + "//build/bazel/product_config/config_settings:binder32bit": ["-Wbinder32bit"], "//conditions:default": [], }) + select({ - "//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"], + "//build/bazel/product_config/config_settings:malloc_not_svelte": ["-Wmalloc_not_svelte"], "//conditions:default": [], }) + select({ - "//build/bazel/product_variables:malloc_zero_contents": ["-Wmalloc_zero_contents"], + "//build/bazel/product_config/config_settings:malloc_zero_contents": ["-Wmalloc_zero_contents"], "//conditions:default": [], })`, "srcs_c": `["common.c"]`, @@ -1216,19 +1248,19 @@ cc_library_static { ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{ "copts": `select({ - "//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"], + "//build/bazel/product_config/config_settings:malloc_not_svelte": ["-Wmalloc_not_svelte"], "//conditions:default": [], }) + select({ - "//build/bazel/product_variables:malloc_not_svelte-android": ["-Wandroid_malloc_not_svelte"], + "//build/bazel/product_config/config_settings:malloc_not_svelte-android": ["-Wandroid_malloc_not_svelte"], "//conditions:default": [], }) + select({ - "//build/bazel/product_variables:malloc_not_svelte-arm": ["-Wlib32_malloc_not_svelte"], + "//build/bazel/product_config/config_settings:malloc_not_svelte-arm": ["-Wlib32_malloc_not_svelte"], "//conditions:default": [], }) + select({ - "//build/bazel/product_variables:malloc_not_svelte-arm64": ["-Warm64_malloc_not_svelte"], + "//build/bazel/product_config/config_settings:malloc_not_svelte-arm64": ["-Warm64_malloc_not_svelte"], "//conditions:default": [], }) + select({ - "//build/bazel/product_variables:malloc_not_svelte-x86": ["-Wlib32_malloc_not_svelte"], + "//build/bazel/product_config/config_settings:malloc_not_svelte-x86": ["-Wlib32_malloc_not_svelte"], "//conditions:default": [], })`, "srcs_c": `["common.c"]`, @@ -1255,7 +1287,7 @@ cc_library_static { ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{ "asflags": `select({ - "//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"], + "//build/bazel/product_config/config_settings:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"], "//conditions:default": [], })`, "srcs_as": `["common.S"]`, @@ -1918,7 +1950,14 @@ cc_library_static { `, ExpectedBazelTargets: []string{ MakeBazelTarget("cc_library_static", "foo", AttrNameToString{ - "features": `["ubsan_blocklist_foo_blocklist_txt"]`, + "copts": `select({ + "//build/bazel/rules/cc:sanitizers_enabled": ["-fsanitize-ignorelist=$(location foo_blocklist.txt)"], + "//conditions:default": [], + })`, + "additional_compiler_inputs": `select({ + "//build/bazel/rules/cc:sanitizers_enabled": [":foo_blocklist.txt"], + "//conditions:default": [], + })`, "local_includes": `["."]`, }), }, @@ -2215,3 +2254,38 @@ cc_library_static{ ]`, })}}) } + +func TestCcLibraryWithProtoInGeneratedSrcs(t *testing.T) { + runCcLibraryStaticTestCase(t, Bp2buildTestCase{ + Description: "cc_library with a .proto file generated from a genrule", + ModuleTypeUnderTest: "cc_library_static", + ModuleTypeUnderTestFactory: cc.LibraryStaticFactory, + Blueprint: soongCcLibraryPreamble + ` +cc_library_static { + name: "mylib", + generated_sources: ["myprotogen"], +} +genrule { + name: "myprotogen", + out: ["myproto.proto"], +} +` + simpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"), + ExpectedBazelTargets: []string{ + MakeBazelTarget("cc_library_static", "mylib", AttrNameToString{ + "local_includes": `["."]`, + "deps": `[":libprotobuf-cpp-lite"]`, + "implementation_whole_archive_deps": `[":mylib_cc_proto_lite"]`, + }), + MakeBazelTarget("cc_lite_proto_library", "mylib_cc_proto_lite", AttrNameToString{ + "deps": `[":mylib_proto"]`, + }), + MakeBazelTarget("proto_library", "mylib_proto", AttrNameToString{ + "srcs": `[":myprotogen"]`, + }), + MakeBazelTargetNoRestrictions("genrule", "myprotogen", AttrNameToString{ + "cmd": `""`, + "outs": `["myproto.proto"]`, + }), + }, + }) +} diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go index eab84e152..ecfcb5a93 100644 --- a/bp2build/cc_object_conversion_test.go +++ b/bp2build/cc_object_conversion_test.go @@ -200,7 +200,7 @@ func TestCcObjectProductVariable(t *testing.T) { ExpectedBazelTargets: []string{ MakeBazelTarget("cc_object", "foo", AttrNameToString{ "asflags": `select({ - "//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"], + "//build/bazel/product_config/config_settings:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"], "//conditions:default": [], })`, "copts": `["-fno-addrsig"]`, diff --git a/bp2build/cc_test_conversion_test.go b/bp2build/cc_test_conversion_test.go index 4df4d4d46..3c037b494 100644 --- a/bp2build/cc_test_conversion_test.go +++ b/bp2build/cc_test_conversion_test.go @@ -94,7 +94,9 @@ cc_test_library { simpleModuleDoNotConvertBp2build("genrule", "data_mod") + simpleModuleDoNotConvertBp2build("cc_binary", "cc_bin") + simpleModuleDoNotConvertBp2build("cc_library", "cc_lib") + - simpleModuleDoNotConvertBp2build("cc_test_library", "cc_test_lib2"), + simpleModuleDoNotConvertBp2build("cc_test_library", "cc_test_lib2") + + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") + + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"), targets: []testBazelTarget{ {"cc_library_shared", "cc_test_lib1", AttrNameToString{}}, {"cc_library_static", "cc_test_lib1_bp2build_cc_library_static", AttrNameToString{}}, @@ -106,7 +108,11 @@ cc_test_library { ":cc_bin", ":cc_lib", ]`, - "deps": `[":cc_test_lib1_bp2build_cc_library_static"] + select({ + "deps": `[ + ":cc_test_lib1_bp2build_cc_library_static", + ":libgtest_main", + ":libgtest", + ] + select({ "//build/bazel/platforms/os:darwin": [":hostlib"], "//build/bazel/platforms/os:linux_bionic": [":hostlib"], "//build/bazel/platforms/os:linux_glibc": [":hostlib"], @@ -114,8 +120,6 @@ cc_test_library { "//build/bazel/platforms/os:windows": [":hostlib"], "//conditions:default": [], })`, - "gtest": "True", - "isolated": "True", "local_includes": `["."]`, "dynamic_deps": `[":cc_test_lib2"] + select({ "//build/bazel/platforms/os:android": [":foolib"], @@ -152,7 +156,6 @@ cc_test { targets: []testBazelTarget{ {"cc_test", "mytest", AttrNameToString{ "gtest": "False", - "isolated": "False", "local_includes": `["."]`, "srcs": `["test.cpp"]`, }, @@ -171,14 +174,17 @@ cc_test { srcs: ["test.cpp"], test_options: { tags: ["no-remote"] }, } -`, +` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") + + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"), targets: []testBazelTarget{ {"cc_test", "mytest", AttrNameToString{ "tags": `["no-remote"]`, "local_includes": `["."]`, "srcs": `["test.cpp"]`, - "gtest": "True", - "isolated": "True", + "deps": `[ + ":libgtest_main", + ":libgtest", + ]`, }, }, }, @@ -197,15 +203,18 @@ cc_test { srcs: ["test.cpp"], test_config: "test_config.xml", } -`, +` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") + + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"), targets: []testBazelTarget{ {"cc_test", "mytest", AttrNameToString{ - "gtest": "True", - "isolated": "True", "local_includes": `["."]`, "srcs": `["test.cpp"]`, "target_compatible_with": `["//build/bazel/platforms/os:android"]`, "test_config": `"test_config.xml"`, + "deps": `[ + ":libgtest_main", + ":libgtest", + ]`, }, }, }, @@ -223,15 +232,18 @@ cc_test { name: "mytest", srcs: ["test.cpp"], } -`, +` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") + + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"), targets: []testBazelTarget{ {"cc_test", "mytest", AttrNameToString{ - "gtest": "True", - "isolated": "True", "local_includes": `["."]`, "srcs": `["test.cpp"]`, "target_compatible_with": `["//build/bazel/platforms/os:android"]`, "test_config": `"AndroidTest.xml"`, + "deps": `[ + ":libgtest_main", + ":libgtest", + ]`, }, }, }, @@ -250,13 +262,13 @@ cc_test { srcs: ["test.cpp"], test_config_template: "test_config_template.xml", auto_gen_config: true, + isolated: true, } -`, +` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_isolated_main") + + simpleModuleDoNotConvertBp2build("cc_library", "liblog"), targets: []testBazelTarget{ {"cc_test", "mytest", AttrNameToString{ "auto_generate_test_config": "True", - "gtest": "True", - "isolated": "True", "local_includes": `["."]`, "srcs": `["test.cpp"]`, "target_compatible_with": `["//build/bazel/platforms/os:android"]`, @@ -266,6 +278,95 @@ cc_test { ]`, "template_install_base": `"/data/local/tmp"`, "template_test_config": `"test_config_template.xml"`, + "deps": `[":libgtest_isolated_main"]`, + "dynamic_deps": `[":liblog"]`, + }, + }, + }, + }) +} + +func TestCcTest_WithExplicitGTestDepInAndroidBp(t *testing.T) { + runCcTestTestCase(t, ccTestBp2buildTestCase{ + description: "cc test that lists libgtest in Android.bp should not have dups of libgtest in BUILD file", + blueprint: ` +cc_test { + name: "mytest", + srcs: ["test.cpp"], + static_libs: ["libgtest"], +} +` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") + + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"), + targets: []testBazelTarget{ + {"cc_test", "mytest", AttrNameToString{ + "local_includes": `["."]`, + "srcs": `["test.cpp"]`, + "target_compatible_with": `["//build/bazel/platforms/os:android"]`, + "deps": `[ + ":libgtest", + ":libgtest_main", + ]`, + }, + }, + }, + }) + +} + +func TestCcTest_WithIsolatedTurnedOn(t *testing.T) { + runCcTestTestCase(t, ccTestBp2buildTestCase{ + description: "cc test that sets `isolated: true` should run with ligtest_isolated_main instead of libgtest_main", + blueprint: ` +cc_test { + name: "mytest", + srcs: ["test.cpp"], + isolated: true, +} +` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_isolated_main") + + simpleModuleDoNotConvertBp2build("cc_library", "liblog"), + targets: []testBazelTarget{ + {"cc_test", "mytest", AttrNameToString{ + "local_includes": `["."]`, + "srcs": `["test.cpp"]`, + "target_compatible_with": `["//build/bazel/platforms/os:android"]`, + "deps": `[":libgtest_isolated_main"]`, + "dynamic_deps": `[":liblog"]`, + }, + }, + }, + }) + +} + +func TestCcTest_GtestExplicitlySpecifiedInAndroidBp(t *testing.T) { + runCcTestTestCase(t, ccTestBp2buildTestCase{ + description: "If `gtest` is explicit in Android.bp, it should be explicit in BUILD files as well", + blueprint: ` +cc_test { + name: "mytest_with_gtest", + gtest: true, +} +cc_test { + name: "mytest_with_no_gtest", + gtest: false, +} +` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") + + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"), + targets: []testBazelTarget{ + {"cc_test", "mytest_with_gtest", AttrNameToString{ + "local_includes": `["."]`, + "deps": `[ + ":libgtest_main", + ":libgtest", + ]`, + "gtest": "True", + "target_compatible_with": `["//build/bazel/platforms/os:android"]`, + }, + }, + {"cc_test", "mytest_with_no_gtest", AttrNameToString{ + "local_includes": `["."]`, + "gtest": "False", + "target_compatible_with": `["//build/bazel/platforms/os:android"]`, }, }, }, diff --git a/bp2build/conversion.go b/bp2build/conversion.go index d5f2386c3..f28092431 100644 --- a/bp2build/conversion.go +++ b/bp2build/conversion.go @@ -1,7 +1,6 @@ package bp2build import ( - "android/soong/starlark_fmt" "encoding/json" "fmt" "reflect" @@ -9,11 +8,11 @@ import ( "strings" "android/soong/android" + "android/soong/apex" "android/soong/cc" cc_config "android/soong/cc/config" java_config "android/soong/java/config" - - "android/soong/apex" + "android/soong/starlark_fmt" "github.com/google/blueprint/proptools" ) @@ -105,12 +104,7 @@ platform_versions = struct( `, starlark_fmt.PrintBool(cfg.PlatformSdkFinal()), platformSdkVersion, cfg.PlatformSdkCodename(), strings.Join(platformVersionActiveCodenames, ", ")) } -func CreateBazelFiles( - cfg android.Config, - ruleShims map[string]RuleShim, - buildToTargets map[string]BazelTargets, - mode CodegenMode) []BazelFile { - +func CreateBazelFiles(ruleShims map[string]RuleShim, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile { var files []BazelFile if mode == QueryView { diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go index 00ffd793e..15284ce03 100644 --- a/bp2build/conversion_test.go +++ b/bp2build/conversion_test.go @@ -27,8 +27,7 @@ type bazelFilepath struct { } func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) { - files := CreateBazelFiles(android.NullConfig("out", "out/soong"), - map[string]RuleShim{}, map[string]BazelTargets{}, QueryView) + files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, QueryView) expectedFilePaths := []bazelFilepath{ { dir: "", diff --git a/bp2build/filegroup_conversion_test.go b/bp2build/filegroup_conversion_test.go index 7ce559d9b..cb2e2076a 100644 --- a/bp2build/filegroup_conversion_test.go +++ b/bp2build/filegroup_conversion_test.go @@ -137,7 +137,7 @@ filegroup { path: "proto", }`, ExpectedBazelTargets: []string{ - MakeBazelTargetNoRestrictions("proto_library", "foo_bp2build_converted", AttrNameToString{ + MakeBazelTargetNoRestrictions("proto_library", "foo_proto", AttrNameToString{ "srcs": `["proto/foo.proto"]`, "strip_import_prefix": `"proto"`, "tags": `[ @@ -145,6 +145,13 @@ filegroup { "manual", ]`, }), + MakeBazelTargetNoRestrictions("alias", "foo_bp2build_converted", AttrNameToString{ + "actual": `"//.:foo_proto"`, + "tags": `[ + "apex_available=//apex_available:anyapex", + "manual", + ]`, + }), MakeBazelTargetNoRestrictions("filegroup", "foo", AttrNameToString{ "srcs": `["proto/foo.proto"]`}), }}) @@ -170,3 +177,27 @@ filegroup { ]`}), }}) } + +func TestFilegroupWithProtoInDifferentPackage(t *testing.T) { + runFilegroupTestCase(t, Bp2buildTestCase{ + Description: "filegroup with .proto in different package", + Filesystem: map[string]string{ + "subdir/Android.bp": "", + }, + Blueprint: ` +filegroup { + name: "foo", + srcs: ["subdir/foo.proto"], +}`, + Dir: "subdir", // check in subdir + ExpectedBazelTargets: []string{ + MakeBazelTargetNoRestrictions("proto_library", "foo_proto", AttrNameToString{ + "srcs": `["//subdir:foo.proto"]`, + "import_prefix": `"subdir"`, + "strip_import_prefix": `""`, + "tags": `[ + "apex_available=//apex_available:anyapex", + "manual", + ]`}), + }}) +} diff --git a/bp2build/genrule_conversion_test.go b/bp2build/genrule_conversion_test.go index 5cf4fb216..2a10a14d4 100644 --- a/bp2build/genrule_conversion_test.go +++ b/bp2build/genrule_conversion_test.go @@ -16,6 +16,7 @@ package bp2build import ( "fmt" + "path/filepath" "testing" "android/soong/android" @@ -26,6 +27,8 @@ import ( func registerGenruleModuleTypes(ctx android.RegistrationContext) { ctx.RegisterModuleType("genrule_defaults", func() android.Module { return genrule.DefaultsFactory() }) + ctx.RegisterModuleType("cc_binary", func() android.Module { return cc.BinaryFactory() }) + ctx.RegisterModuleType("soong_namespace", func() android.Module { return android.NamespaceFactory() }) } func runGenruleTestCase(t *testing.T, tc Bp2buildTestCase) { @@ -695,3 +698,257 @@ func TestCcGenruleArchAndExcludeSrcs(t *testing.T) { }) }) } + +func TestGenruleWithExportIncludeDirs(t *testing.T) { + testCases := []struct { + moduleType string + factory android.ModuleFactory + hod android.HostOrDeviceSupported + }{ + { + moduleType: "genrule", + factory: genrule.GenRuleFactory, + }, + { + moduleType: "cc_genrule", + factory: cc.GenRuleFactory, + hod: android.DeviceSupported, + }, + { + moduleType: "java_genrule", + factory: java.GenRuleFactory, + hod: android.DeviceSupported, + }, + { + moduleType: "java_genrule_host", + factory: java.GenRuleFactoryHost, + hod: android.HostSupported, + }, + } + + dir := "baz" + + bp := `%s { + name: "foo", + out: ["foo.out.h"], + srcs: ["foo.in"], + cmd: "cp $(in) $(out)", + export_include_dirs: ["foo", "bar", "."], + bazel_module: { bp2build_available: true }, +}` + + for _, tc := range testCases { + moduleAttrs := AttrNameToString{ + "cmd": `"cp $(SRCS) $(OUTS)"`, + "outs": `["foo.out.h"]`, + "srcs": `["foo.in"]`, + } + + expectedBazelTargets := []string{ + makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod), + makeBazelTargetHostOrDevice("cc_library_headers", "foo__header_library", AttrNameToString{ + "hdrs": `[":foo"]`, + "export_includes": `[ + "foo", + "baz/foo", + "bar", + "baz/bar", + ".", + "baz", + ]`, + }, + tc.hod), + } + + t.Run(tc.moduleType, func(t *testing.T) { + RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, + Bp2buildTestCase{ + ModuleTypeUnderTest: tc.moduleType, + ModuleTypeUnderTestFactory: tc.factory, + Filesystem: map[string]string{ + filepath.Join(dir, "Android.bp"): fmt.Sprintf(bp, tc.moduleType), + }, + Dir: dir, + ExpectedBazelTargets: expectedBazelTargets, + }) + }) + } +} + +func TestGenruleWithSoongConfigVariableConfiguredCmd(t *testing.T) { + testCases := []struct { + moduleType string + factory android.ModuleFactory + hod android.HostOrDeviceSupported + }{ + { + moduleType: "genrule", + factory: genrule.GenRuleFactory, + }, + { + moduleType: "cc_genrule", + factory: cc.GenRuleFactory, + hod: android.DeviceSupported, + }, + { + moduleType: "java_genrule", + factory: java.GenRuleFactory, + hod: android.DeviceSupported, + }, + { + moduleType: "java_genrule_host", + factory: java.GenRuleFactoryHost, + hod: android.HostSupported, + }, + } + + bp := ` +soong_config_module_type { + name: "my_genrule", + module_type: "%s", + config_namespace: "my_namespace", + bool_variables: ["my_variable"], + properties: ["cmd"], +} + +my_genrule { + name: "foo", + out: ["foo.txt"], + cmd: "echo 'no variable' > $(out)", + soong_config_variables: { + my_variable: { + cmd: "echo 'with variable' > $(out)", + }, + }, + bazel_module: { bp2build_available: true }, +} +` + + for _, tc := range testCases { + moduleAttrs := AttrNameToString{ + "cmd": `select({ + "//build/bazel/product_config/config_settings:my_namespace__my_variable": "echo 'with variable' > $(OUTS)", + "//conditions:default": "echo 'no variable' > $(OUTS)", + })`, + "outs": `["foo.txt"]`, + } + + expectedBazelTargets := []string{ + makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod), + } + + t.Run(tc.moduleType, func(t *testing.T) { + RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) { android.RegisterSoongConfigModuleBuildComponents(ctx) }, + Bp2buildTestCase{ + Blueprint: fmt.Sprintf(bp, tc.moduleType), + ModuleTypeUnderTest: tc.moduleType, + ModuleTypeUnderTestFactory: tc.factory, + ExpectedBazelTargets: expectedBazelTargets, + }) + }) + } +} + +func TestGenruleWithProductVariableConfiguredCmd(t *testing.T) { + testCases := []struct { + moduleType string + factory android.ModuleFactory + hod android.HostOrDeviceSupported + }{ + { + moduleType: "genrule", + factory: genrule.GenRuleFactory, + }, + { + moduleType: "cc_genrule", + factory: cc.GenRuleFactory, + hod: android.DeviceSupported, + }, + { + moduleType: "java_genrule", + factory: java.GenRuleFactory, + hod: android.DeviceSupported, + }, + { + moduleType: "java_genrule_host", + factory: java.GenRuleFactoryHost, + hod: android.HostSupported, + }, + } + + bp := ` + +%s { + name: "foo", + out: ["foo.txt"], + cmd: "echo 'no variable' > $(out)", + product_variables: { + debuggable: { + cmd: "echo 'with variable' > $(out)", + }, + }, + bazel_module: { bp2build_available: true }, +} +` + + for _, tc := range testCases { + moduleAttrs := AttrNameToString{ + "cmd": `select({ + "//build/bazel/product_config/config_settings:debuggable": "echo 'with variable' > $(OUTS)", + "//conditions:default": "echo 'no variable' > $(OUTS)", + })`, + "outs": `["foo.txt"]`, + } + + expectedBazelTargets := []string{ + makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod), + } + + t.Run(tc.moduleType, func(t *testing.T) { + RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) { android.RegisterSoongConfigModuleBuildComponents(ctx) }, + Bp2buildTestCase{ + Blueprint: fmt.Sprintf(bp, tc.moduleType), + ModuleTypeUnderTest: tc.moduleType, + ModuleTypeUnderTestFactory: tc.factory, + ExpectedBazelTargets: expectedBazelTargets, + }) + }) + } +} + +func TestGenruleWithModulesInNamespaces(t *testing.T) { + bp := ` +genrule { + name: "mygenrule", + cmd: "echo $(location //mynamespace:mymodule) > $(out)", + srcs: ["//mynamespace:mymodule"], + out: ["myout"], +} +` + fs := map[string]string{ + "mynamespace/Android.bp": `soong_namespace {}`, + "mynamespace/dir/Android.bp": `cc_binary {name: "mymodule"}`, + } + expectedBazelTargets := []string{ + MakeBazelTargetNoRestrictions("genrule", "mygenrule", AttrNameToString{ + // The fully qualified soong label is <namespace>:<module_name> + // - here the prefix is mynamespace + // The fully qualifed bazel label is <package>:<module_name> + // - here the prefix is mynamespace/dir, since there is a BUILD file at each level of this FS path + "cmd": `"echo $(location //mynamespace/dir:mymodule) > $(OUTS)"`, + "outs": `["myout"]`, + "srcs": `["//mynamespace/dir:mymodule"]`, + }), + } + + t.Run("genrule that uses module from a different namespace", func(t *testing.T) { + runGenruleTestCase(t, Bp2buildTestCase{ + Blueprint: bp, + Filesystem: fs, + ModuleTypeUnderTest: "genrule", + ModuleTypeUnderTestFactory: genrule.GenRuleFactory, + ExpectedBazelTargets: expectedBazelTargets, + }) + }) + +} diff --git a/bp2build/go_conversion_test.go b/bp2build/go_conversion_test.go new file mode 100644 index 000000000..2387641f2 --- /dev/null +++ b/bp2build/go_conversion_test.go @@ -0,0 +1,208 @@ +// 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", + ], + testSrcs: [ + "foo_linux_test.go", + ], + }, + darwin: { + srcs: [ + "foo_darwin.go", + ], + testSrcs: [ + "foo_darwin_test.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, + ), + makeBazelTargetHostOrDevice("go_test", "foo-test", + AttrNameToString{ + "embed": `[":foo"]`, + "srcs": `[ + "foo1_test.go", + "foo2_test.go", + ] + select({ + "//build/bazel/platforms/os:darwin": ["foo_darwin_test.go"], + "//build/bazel/platforms/os:linux_glibc": ["foo_linux_test.go"], + "//conditions:default": [], + })`, + }, + android.HostSupported, + )}, + }) +} + +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 TestConvertGoBinaryWithTestSrcs(t *testing.T) { + bp := ` +blueprint_go_binary { + name: "foo", + srcs: ["main.go"], + testSrcs: ["main_test.go"], +} +` + t.Parallel() + runGoTests(t, Bp2buildTestCase{ + Description: "Convert blueprint_go_binary with testSrcs", + Blueprint: bp, + ExpectedBazelTargets: []string{ + makeBazelTargetHostOrDevice("go_binary", "foo", + AttrNameToString{ + "deps": `[]`, + "embed": `[":foo-source"]`, + }, + android.HostSupported, + ), + makeBazelTargetHostOrDevice("go_source", "foo-source", + AttrNameToString{ + "deps": `[]`, + "srcs": `["main.go"]`, + }, + android.HostSupported, + ), + makeBazelTargetHostOrDevice("go_test", "foo-test", + AttrNameToString{ + "embed": `[":foo-source"]`, + "srcs": `["main_test.go"]`, + }, + android.HostSupported, + ), + }, + }) +} + +func TestConvertGoBinaryWithSrcInDifferentPackage(t *testing.T) { + bp := ` +blueprint_go_binary { + 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/bp2build/prebuilt_etc_conversion_test.go b/bp2build/prebuilt_etc_conversion_test.go index aa0a5b728..5b2d609ac 100644 --- a/bp2build/prebuilt_etc_conversion_test.go +++ b/bp2build/prebuilt_etc_conversion_test.go @@ -149,7 +149,7 @@ prebuilt_etc { MakeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{ "filename": `"tz_version"`, "src": `select({ - "//build/bazel/product_variables:native_coverage": "src1", + "//build/bazel/product_config/config_settings:native_coverage": "src1", "//conditions:default": "version/tz_version", })`, "dir": `"etc"`, @@ -318,7 +318,7 @@ prebuilt_etc { "dir": `"etc"`, "src": `select({ "//build/bazel/platforms/arch:arm": "armSrc", - "//build/bazel/product_variables:native_coverage-arm": "nativeCoverageArmSrc", + "//build/bazel/product_config/config_settings:native_coverage-arm": "nativeCoverageArmSrc", "//conditions:default": None, })`, })}}) diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go index 813773d00..8302ce87b 100644 --- a/bp2build/soong_config_module_type_conversion_test.go +++ b/bp2build/soong_config_module_type_conversion_test.go @@ -91,7 +91,7 @@ custom_cc_library_static { ExpectedBazelTargets: []string{`cc_library_static( name = "foo", copts = select({ - "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"], + "//build/bazel/product_config/config_settings:acme__feature1": ["-DFEATURE1"], "//conditions:default": ["-DDEFAULT1"], }), local_includes = ["."], @@ -140,7 +140,7 @@ custom_cc_library_static { ExpectedBazelTargets: []string{`cc_library_static( name = "foo", copts = select({ - "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"], + "//build/bazel/product_config/config_settings:acme__feature1": ["-DFEATURE1"], "//conditions:default": ["-DDEFAULT1"], }), local_includes = ["."], @@ -191,9 +191,9 @@ custom_cc_library_static { ExpectedBazelTargets: []string{`cc_library_static( name = "foo", copts = select({ - "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"], - "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"], - "//build/bazel/product_variables:acme__board__soc_c": [], + "//build/bazel/product_config/config_settings:acme__board__soc_a": ["-DSOC_A"], + "//build/bazel/product_config/config_settings:acme__board__soc_b": ["-DSOC_B"], + "//build/bazel/product_config/config_settings:acme__board__soc_c": [], "//conditions:default": ["-DSOC_DEFAULT"], }), local_includes = ["."], @@ -240,7 +240,7 @@ custom_cc_library_static { ExpectedBazelTargets: []string{`cc_library_static( name = "foo", copts = select({ - "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"], + "//build/bazel/product_config/config_settings:acme__feature1": ["-DFEATURE1"], "//conditions:default": ["-DDEFAULT1"], }), local_includes = ["."], @@ -310,15 +310,15 @@ custom_cc_library_static { ExpectedBazelTargets: []string{`cc_library_static( name = "foo", copts = select({ - "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"], - "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"], - "//build/bazel/product_variables:acme__board__soc_c": [], + "//build/bazel/product_config/config_settings:acme__board__soc_a": ["-DSOC_A"], + "//build/bazel/product_config/config_settings:acme__board__soc_b": ["-DSOC_B"], + "//build/bazel/product_config/config_settings:acme__board__soc_c": [], "//conditions:default": ["-DSOC_DEFAULT"], }) + select({ - "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"], + "//build/bazel/product_config/config_settings:acme__feature1": ["-DFEATURE1"], "//conditions:default": ["-DDEFAULT1"], }) + select({ - "//build/bazel/product_variables:acme__feature2": ["-DFEATURE2"], + "//build/bazel/product_config/config_settings:acme__feature2": ["-DFEATURE2"], "//conditions:default": ["-DDEFAULT2"], }), local_includes = ["."], @@ -380,15 +380,15 @@ cc_library_static { name: "soc_default_static_dep", bazel_module: { bp2build_ava ExpectedBazelTargets: []string{`cc_library_static( name = "foo", copts = select({ - "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"], - "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"], - "//build/bazel/product_variables:acme__board__soc_c": [], + "//build/bazel/product_config/config_settings:acme__board__soc_a": ["-DSOC_A"], + "//build/bazel/product_config/config_settings:acme__board__soc_b": ["-DSOC_B"], + "//build/bazel/product_config/config_settings:acme__board__soc_c": [], "//conditions:default": ["-DSOC_DEFAULT"], }), implementation_deps = select({ - "//build/bazel/product_variables:acme__board__soc_a": ["//foo/bar:soc_a_dep"], - "//build/bazel/product_variables:acme__board__soc_b": ["//foo/bar:soc_b_dep"], - "//build/bazel/product_variables:acme__board__soc_c": [], + "//build/bazel/product_config/config_settings:acme__board__soc_a": ["//foo/bar:soc_a_dep"], + "//build/bazel/product_config/config_settings:acme__board__soc_b": ["//foo/bar:soc_b_dep"], + "//build/bazel/product_config/config_settings:acme__board__soc_c": [], "//conditions:default": ["//foo/bar:soc_default_static_dep"], }), local_includes = ["."], @@ -446,7 +446,7 @@ cc_library_static { ExpectedBazelTargets: []string{`cc_library_static( name = "lib", copts = select({ - "//build/bazel/product_variables:vendor_foo__feature": [ + "//build/bazel/product_config/config_settings:vendor_foo__feature": [ "-cflag_feature_2", "-cflag_feature_1", ], @@ -527,11 +527,11 @@ cc_library_static { ExpectedBazelTargets: []string{`cc_library_static( name = "lib", asflags = select({ - "//build/bazel/product_variables:acme__feature": ["-asflag_bar"], + "//build/bazel/product_config/config_settings:acme__feature": ["-asflag_bar"], "//conditions:default": ["-asflag_default_bar"], }), copts = select({ - "//build/bazel/product_variables:acme__feature": [ + "//build/bazel/product_config/config_settings:acme__feature": [ "-cflag_foo", "-cflag_bar", ], @@ -546,11 +546,11 @@ cc_library_static { `cc_library_static( name = "lib2", asflags = select({ - "//build/bazel/product_variables:acme__feature": ["-asflag_bar"], + "//build/bazel/product_config/config_settings:acme__feature": ["-asflag_bar"], "//conditions:default": ["-asflag_default_bar"], }), copts = select({ - "//build/bazel/product_variables:acme__feature": [ + "//build/bazel/product_config/config_settings:acme__feature": [ "-cflag_bar", "-cflag_foo", ], @@ -643,13 +643,13 @@ cc_library_static { ExpectedBazelTargets: []string{`cc_library_static( name = "lib", copts = select({ - "//build/bazel/product_variables:vendor_bar__feature": ["-DVENDOR_BAR_FEATURE"], + "//build/bazel/product_config/config_settings:vendor_bar__feature": ["-DVENDOR_BAR_FEATURE"], "//conditions:default": ["-DVENDOR_BAR_DEFAULT"], }) + select({ - "//build/bazel/product_variables:vendor_foo__feature": ["-DVENDOR_FOO_FEATURE"], + "//build/bazel/product_config/config_settings:vendor_foo__feature": ["-DVENDOR_FOO_FEATURE"], "//conditions:default": ["-DVENDOR_FOO_DEFAULT"], }) + select({ - "//build/bazel/product_variables:vendor_qux__feature": ["-DVENDOR_QUX_FEATURE"], + "//build/bazel/product_config/config_settings:vendor_qux__feature": ["-DVENDOR_QUX_FEATURE"], "//conditions:default": ["-DVENDOR_QUX_DEFAULT"], }), local_includes = ["."], @@ -697,7 +697,7 @@ library_linking_strategy_custom { ExpectedBazelTargets: []string{ MakeBazelTarget("custom", "foo", AttrNameToString{ "string_literal_prop": `select({ - "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": "29", + "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": "29", "//conditions:default": "30", })`, }), @@ -779,7 +779,7 @@ cc_library { name: "lib_default", bazel_module: { bp2build_available: false } } ExpectedBazelTargets: []string{`cc_binary( name = "library_linking_strategy_sample_binary", dynamic_deps = select({ - "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [], + "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [], "//conditions:default": [ "//foo/bar:lib_b", "//foo/bar:lib_a", @@ -868,7 +868,7 @@ cc_library { name: "lib_c", bazel_module: { bp2build_available: false } } ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("cc_binary", "library_linking_strategy_sample_binary", AttrNameToString{ "dynamic_deps": `select({ - "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [], + "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [], "//conditions:default": [ "//foo/bar:lib_b", "//foo/bar:lib_c", @@ -877,7 +877,7 @@ cc_library { name: "lib_c", bazel_module: { bp2build_available: false } } }), MakeBazelTargetNoRestrictions("cc_binary", "library_linking_strategy_sample_binary_with_excludes", AttrNameToString{ "dynamic_deps": `select({ - "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [], + "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [], "//conditions:default": ["//foo/bar:lib_b"], })`, }), @@ -965,14 +965,14 @@ cc_library { name: "lib_default", bazel_module: { bp2build_available: false } } ExpectedBazelTargets: []string{`cc_binary( name = "library_linking_strategy_sample_binary", deps = select({ - "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [ + "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [ "//foo/bar:lib_b_bp2build_cc_library_static", "//foo/bar:lib_a_bp2build_cc_library_static", ], "//conditions:default": [], }), dynamic_deps = select({ - "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [], + "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [], "//conditions:default": [ "//foo/bar:lib_b", "//foo/bar:lib_a", @@ -1046,14 +1046,14 @@ cc_library { name: "lib_b", bazel_module: { bp2build_available: false } } ExpectedBazelTargets: []string{`cc_binary( name = "library_linking_strategy_sample_binary", deps = select({ - "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [ + "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [ "//foo/bar:lib_a_bp2build_cc_library_static", "//foo/bar:lib_b_bp2build_cc_library_static", ], "//conditions:default": [], }), dynamic_deps = select({ - "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [], + "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [], "//conditions:default": [ "//foo/bar:lib_a", "//foo/bar:lib_b", @@ -1134,13 +1134,13 @@ cc_library { name: "lib_default", bazel_module: { bp2build_available: false } } ExpectedBazelTargets: []string{`cc_binary( name = "alphabet_binary", deps = select({ - "//build/bazel/product_variables:android__alphabet__a": [], - "//build/bazel/product_variables:android__alphabet__b": [], + "//build/bazel/product_config/config_settings:android__alphabet__a": [], + "//build/bazel/product_config/config_settings:android__alphabet__b": [], "//conditions:default": ["//foo/bar:lib_default_bp2build_cc_library_static"], }), dynamic_deps = select({ - "//build/bazel/product_variables:android__alphabet__a": ["//foo/bar:lib_a"], - "//build/bazel/product_variables:android__alphabet__b": ["//foo/bar:lib_b"], + "//build/bazel/product_config/config_settings:android__alphabet__a": ["//foo/bar:lib_a"], + "//build/bazel/product_config/config_settings:android__alphabet__b": ["//foo/bar:lib_b"], "//conditions:default": [], }), local_includes = ["."], @@ -1199,7 +1199,7 @@ cc_binary { name = "alphabet_binary", local_includes = ["."], srcs = ["main.cc"], - target_compatible_with = ["//build/bazel/product_variables:alphabet_module__special_build"] + select({ + target_compatible_with = select({ "//build/bazel/platforms/os_arch:android_x86_64": ["@platforms//:incompatible"], "//build/bazel/platforms/os_arch:darwin_arm64": ["@platforms//:incompatible"], "//build/bazel/platforms/os_arch:darwin_x86_64": ["@platforms//:incompatible"], @@ -1208,6 +1208,9 @@ cc_binary { "//build/bazel/platforms/os_arch:linux_musl_x86_64": ["@platforms//:incompatible"], "//build/bazel/platforms/os_arch:windows_x86_64": ["@platforms//:incompatible"], "//conditions:default": [], + }) + select({ + "//build/bazel/product_config/config_settings:alphabet_module__special_build": [], + "//conditions:default": ["@platforms//:incompatible"], }), )`}}) } @@ -1240,6 +1243,24 @@ cc_binary { srcs: ["main.cc"], defaults: ["alphabet_sample_cc_defaults"], enabled: false, +} + +alphabet_cc_defaults { + name: "alphabet_sample_cc_defaults_conditions_default", + soong_config_variables: { + special_build: { + conditions_default: { + enabled: false, + }, + }, + }, +} + +cc_binary { + name: "alphabet_binary_conditions_default", + srcs: ["main.cc"], + defaults: ["alphabet_sample_cc_defaults_conditions_default"], + enabled: false, }` runSoongConfigModuleTypeTest(t, Bp2buildTestCase{ @@ -1252,8 +1273,17 @@ cc_binary { name = "alphabet_binary", local_includes = ["."], srcs = ["main.cc"], - target_compatible_with = ["//build/bazel/product_variables:alphabet_module__special_build"], -)`}}) + target_compatible_with = select({ + "//build/bazel/product_config/config_settings:alphabet_module__special_build": [], + "//conditions:default": ["@platforms//:incompatible"], + }), +)`, + MakeBazelTarget("cc_binary", "alphabet_binary_conditions_default", AttrNameToString{ + "local_includes": `["."]`, + "srcs": `["main.cc"]`, + "target_compatible_with": `["@platforms//:incompatible"]`, + }), + }}) } func TestSoongConfigModuleType_ProductVariableIgnoredIfEnabledByDefault(t *testing.T) { @@ -1389,16 +1419,16 @@ cc_binary { "//build/bazel/platforms/os:android": ["-DFOO"], "//conditions:default": [], }) + select({ - "//build/bazel/product_variables:my_namespace__my_bool_variable__android": ["-DBAR"], - "//build/bazel/product_variables:my_namespace__my_bool_variable__conditions_default__android": ["-DBAZ"], + "//build/bazel/product_config/config_settings:my_namespace__my_bool_variable__android": ["-DBAR"], + "//build/bazel/product_config/config_settings:my_namespace__my_bool_variable__conditions_default__android": ["-DBAZ"], "//conditions:default": [], }) + select({ - "//build/bazel/product_variables:my_namespace__my_string_variable__value1": ["-DVALUE1_NOT_ANDROID"], + "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__value1": ["-DVALUE1_NOT_ANDROID"], "//conditions:default": [], }) + select({ - "//build/bazel/product_variables:my_namespace__my_string_variable__conditions_default__android": ["-DSTRING_VAR_CONDITIONS_DEFAULT"], - "//build/bazel/product_variables:my_namespace__my_string_variable__value1__android": ["-DVALUE1"], - "//build/bazel/product_variables:my_namespace__my_string_variable__value2__android": ["-DVALUE2"], + "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__conditions_default__android": ["-DSTRING_VAR_CONDITIONS_DEFAULT"], + "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__value1__android": ["-DVALUE1"], + "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__value2__android": ["-DVALUE2"], "//conditions:default": [], }), local_includes = ["."], @@ -1406,3 +1436,166 @@ cc_binary { target_compatible_with = ["//build/bazel/platforms/os:android"], )`}}) } + +// If we have +// A. a soong_config_module_type with target.android_<arch>.* in properties +// B. a module that uses this module type but does not set target.android_<arch>.* via soong config vars +// Then we should not panic +func TestPanicsIfSoongConfigModuleTypeHasArchSpecificProperties(t *testing.T) { + commonBp := ` +soong_config_bool_variable { + name: "my_bool_variable", +} +soong_config_module_type { + name: "special_cc_defaults", + module_type: "cc_defaults", + config_namespace: "my_namespace", + bool_variables: ["my_bool_variable"], + properties: [ + "cflags", + "target.android_arm64.shared_libs", + ], +} +cc_binary { + name: "my_binary", + defaults: ["my_special_cc_defaults"], +} +` + testCases := []struct { + desc string + additionalBp string + isPanicExpected bool + }{ + { + desc: "target.android_arm64 is not set, bp2build should not panic", + additionalBp: ` +special_cc_defaults { + name: "my_special_cc_defaults", + soong_config_variables: { + my_bool_variable: { + cflags: ["-DFOO"], + conditions_default: { + cflags: ["-DBAR"], + } + } + }, +} + `, + isPanicExpected: false, + }, + { + desc: "target.android_arm64 is set using the bool soong config var, bp2build should panic", + additionalBp: ` +special_cc_defaults { + name: "my_special_cc_defaults", + soong_config_variables: { + my_bool_variable: { + cflags: ["-DFOO"], + target: { + android_arm64: { + shared_libs: ["liblog"], + }, + }, + conditions_default: { + cflags: ["-DBAR"], + } + } + }, +} + `, + isPanicExpected: true, + }, + { + desc: "target.android_arm64 is set using conditions_default for the bool soong config var, bp2build should panic", + additionalBp: ` +special_cc_defaults { + name: "my_special_cc_defaults", + soong_config_variables: { + my_bool_variable: { + cflags: ["-DFOO"], + conditions_default: { + cflags: ["-DBAR"], + target: { + android_arm64: { + shared_libs: ["liblog"], + }, + }, + } + } + }, +} + `, + isPanicExpected: true, + }, + } + for _, tc := range testCases { + bp2buildTestCase := Bp2buildTestCase{ + Description: tc.desc, + ModuleTypeUnderTest: "cc_binary", + ModuleTypeUnderTestFactory: cc.BinaryFactory, + Blueprint: commonBp + tc.additionalBp, + // Check in `foo` dir so that we can check whether it panics or not and not trip over an empty `ExpectedBazelTargets` + Dir: "foo", + ExpectedBazelTargets: []string{}, + } + if tc.isPanicExpected { + bp2buildTestCase.ExpectedErr = fmt.Errorf("TODO: support other target types in soong config variable structs: Android_arm64") + } + runSoongConfigModuleTypeTest(t, bp2buildTestCase) + } +} + +func TestNoPanicIfEnabledIsNotUsed(t *testing.T) { + bp := ` +soong_config_string_variable { + name: "my_string_variable", + values: ["val1", "val2"], +} +soong_config_module_type { + name: "special_cc_defaults", + module_type: "cc_defaults", + config_namespace: "my_namespace", + variables: ["my_string_variable"], + properties: [ + "cflags", + "enabled", + ], +} +special_cc_defaults { + name: "my_special_cc_defaults", + soong_config_variables: { + my_string_variable: { + val1: { + cflags: ["-DFOO"], + }, + val2: { + cflags: ["-DBAR"], + }, + }, + }, +} +cc_binary { + name: "my_binary", + enabled: false, + defaults: ["my_special_cc_defaults"], +} +` + tc := Bp2buildTestCase{ + Description: "Soong config vars is not used to set `enabled` property", + ModuleTypeUnderTest: "cc_binary", + ModuleTypeUnderTestFactory: cc.BinaryFactory, + Blueprint: bp, + ExpectedBazelTargets: []string{ + MakeBazelTarget("cc_binary", "my_binary", AttrNameToString{ + "copts": `select({ + "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__val1": ["-DFOO"], + "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__val2": ["-DBAR"], + "//conditions:default": [], + })`, + "local_includes": `["."]`, + "target_compatible_with": `["@platforms//:incompatible"]`, + }), + }, + } + runSoongConfigModuleTypeTest(t, tc) +} diff --git a/bp2build/testing.go b/bp2build/testing.go index 140b214cf..18ae82de9 100644 --- a/bp2build/testing.go +++ b/bp2build/testing.go @@ -336,6 +336,8 @@ type customProps struct { Api *string // File describing the APIs of this module Test_config_setting *bool // Used to test generation of config_setting targets + + Dir *string // Dir in which the Bazel Target will be created } type customModule struct { @@ -461,6 +463,10 @@ type customBazelModuleAttributes struct { Api bazel.LabelAttribute } +func (m *customModule) dir() *string { + return m.props.Dir +} + func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) { if p := m.props.One_to_many_prop; p != nil && *p { customBp2buildOneToMany(ctx, m) @@ -508,7 +514,7 @@ func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) { Rule_class: "custom", } - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs) + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name(), Dir: m.dir()}, attrs) if proptools.Bool(m.props.Test_config_setting) { m.createConfigSetting(ctx) diff --git a/build_kzip.bash b/build_kzip.bash index dddcd3f3f..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}") @@ -71,7 +71,7 @@ done set +e declare -r kzip_count=$(find "$out" -name '*.kzip' | wc -l) -(($kzip_count>100000)) || { printf "Too few kzip files were generated: %d\n" $kzip_count; exit 1; } +(($kzip_count>100000)) || { >&2 printf "ERROR: Too few kzip files were generated: %d\n" $kzip_count; exit 1; } # Pack declare -r allkzip="$KZIP_NAME.kzip" diff --git a/cc/Android.bp b/cc/Android.bp index f49dc1a9e..c32d85490 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -32,10 +32,12 @@ bootstrap_go_package { "check.go", "coverage.go", "gen.go", + "generated_cc_library.go", "image.go", "linkable.go", "lto.go", "makevars.go", + "orderfile.go", "pgo.go", "prebuilt.go", "proto.go", @@ -103,6 +105,7 @@ bootstrap_go_package { "lto_test.go", "ndk_test.go", "object_test.go", + "orderfile_test.go", "prebuilt_test.go", "proto_test.go", "sanitize_test.go", diff --git a/cc/afdo.go b/cc/afdo.go index bc7cd5212..23d196dba 100644 --- a/cc/afdo.go +++ b/cc/afdo.go @@ -131,6 +131,10 @@ func (c *Module) fdoProfileMutator(ctx android.BottomUpMutatorContext) { return } + if !c.afdo.afdoEnabled() { + return + } + ctx.VisitDirectDepsWithTag(FdoProfileTag, func(m android.Module) { if ctx.OtherModuleHasProvider(m, FdoProfileProvider) { info := ctx.OtherModuleProvider(m, FdoProfileProvider).(FdoProfileInfo) diff --git a/cc/api_level.go b/cc/api_level.go index a5571f31f..69a0d3ae4 100644 --- a/cc/api_level.go +++ b/cc/api_level.go @@ -31,7 +31,11 @@ func MinApiForArch(ctx android.EarlyModuleContext, case android.Arm64, android.X86_64: return android.FirstLp64Version case android.Riscv64: - return android.FutureApiLevel + apiLevel, err := android.ApiLevelFromUser(ctx, "VanillaIceCream") + if err != nil { + panic(err) + } + return apiLevel default: panic(fmt.Errorf("Unknown arch %q", arch)) } diff --git a/cc/binary.go b/cc/binary.go index 5ba33a24a..4606b623e 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -638,7 +638,8 @@ func binaryBp2buildAttrs(ctx android.TopDownMutatorContext, m *Module) binaryAtt Stl: baseAttrs.stl, Cpp_std: baseAttrs.cppStd, - Additional_linker_inputs: baseAttrs.additionalLinkerInputs, + Additional_linker_inputs: baseAttrs.additionalLinkerInputs, + Additional_compiler_inputs: baseAttrs.additionalCompilerInputs, Strip: stripAttributes{ Keep_symbols: baseAttrs.stripKeepSymbols, @@ -680,10 +681,11 @@ type binaryAttributes struct { Srcs_c bazel.LabelListAttribute Srcs_as bazel.LabelListAttribute - Copts bazel.StringListAttribute - Cppflags bazel.StringListAttribute - Conlyflags bazel.StringListAttribute - Asflags bazel.StringListAttribute + Copts bazel.StringListAttribute + Cppflags bazel.StringListAttribute + Conlyflags bazel.StringListAttribute + Asflags bazel.StringListAttribute + Additional_compiler_inputs bazel.LabelListAttribute Deps bazel.LabelListAttribute Dynamic_deps bazel.LabelListAttribute diff --git a/cc/bp2build.go b/cc/bp2build.go index 5459595e2..0157632aa 100644 --- a/cc/bp2build.go +++ b/cc/bp2build.go @@ -22,6 +22,7 @@ import ( "android/soong/android" "android/soong/bazel" "android/soong/cc/config" + "android/soong/genrule" "github.com/google/blueprint" @@ -43,6 +44,14 @@ const ( rScriptSrcPartition = "renderScript" + xsdSrcPartition = "xsd" + + genrulePartition = "genrule" + + protoFromGenPartition = "proto_gen" + + hdrPartition = "hdr" + stubsSuffix = "_stub_libs_current" ) @@ -56,6 +65,8 @@ type staticOrSharedAttributes struct { Hdrs bazel.LabelListAttribute Copts bazel.StringListAttribute + Additional_compiler_inputs bazel.LabelListAttribute + Deps bazel.LabelListAttribute Implementation_deps bazel.LabelListAttribute Dynamic_deps bazel.LabelListAttribute @@ -119,6 +130,41 @@ func (m *Module) convertTidyAttributes(ctx android.BaseMutatorContext, moduleAtt } } +// Returns an unchanged label and a bool indicating whether the dep is a genrule that produces .proto files +func protoFromGenPartitionMapper(pathCtx android.BazelConversionContext) bazel.LabelMapper { + return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) { + mod, exists := ctx.ModuleFromName(label.OriginalModuleName) + if !exists { + return label.Label, false + } + gen, isGen := mod.(*genrule.Module) + if !isGen { + return label.Label, false + } + if containsProto(ctx, gen.RawOutputFiles(pathCtx)) { + // Return unmodified label + true + // True will ensure that this module gets dropped from `srcs` of the generated cc_* target. `srcs` is reserved for .cpp files + return label.Label, true + } + return label.Label, false + } +} + +// Returns true if srcs contains only .proto files +// Raises an exception if there is a combination of .proto and non .proto srcs +func containsProto(ctx bazel.OtherModuleContext, srcs []string) bool { + onlyProtos := false + for _, src := range srcs { + if strings.HasSuffix(src, ".proto") { + onlyProtos = true + } else if onlyProtos { + // This is not a proto file, and we have encountered a .proto file previously + ctx.ModuleErrorf("TOOD: Add bp2build support combination of .proto and non .proto files in outs of genrule") + } + } + return onlyProtos +} + // groupSrcsByExtension partitions `srcs` into groups based on file extension. func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute { // Convert filegroup dependencies into extension-specific filegroups filtered in the filegroup.bzl @@ -152,9 +198,11 @@ func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.Lab // contains .l or .ll files we will need to find a way to add a // LabelMapper for these that identifies these filegroups and // converts them appropriately - lSrcPartition: bazel.LabelPartition{Extensions: []string{".l"}}, - llSrcPartition: bazel.LabelPartition{Extensions: []string{".ll"}}, - rScriptSrcPartition: bazel.LabelPartition{Extensions: []string{".fs", ".rscript"}}, + 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)}, + protoFromGenPartition: bazel.LabelPartition{LabelMapper: protoFromGenPartitionMapper(ctx)}, // 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 +213,15 @@ func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.Lab return bazel.PartitionLabelListAttribute(ctx, &srcs, labels) } +func partitionHeaders(ctx android.BazelConversionPathContext, hdrs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute { + labels := bazel.LabelPartitions{ + xsdSrcPartition: bazel.LabelPartition{LabelMapper: android.XsdLabelMapper(xsdConfigCppTarget)}, + genrulePartition: bazel.LabelPartition{LabelMapper: genrule.GenruleCcHeaderLabelMapper}, + hdrPartition: bazel.LabelPartition{Keep_remainder: true}, + } + return bazel.PartitionLabelListAttribute(ctx, &hdrs, labels) +} + // bp2BuildParseLibProps returns the attributes for a variant of a cc_library. func bp2BuildParseLibProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) staticOrSharedAttributes { lib, ok := module.compiler.(*libraryDecorator) @@ -403,7 +460,12 @@ type compilerAttributes struct { srcs bazel.LabelListAttribute // xsd config sources - xsdInSrcs bazel.StringListAttribute + xsdSrcs bazel.LabelListAttribute + exportXsdSrcs bazel.LabelListAttribute + + // genrule headers + genruleHeaders bazel.LabelListAttribute + exportGenruleHeaders bazel.LabelListAttribute // Lex sources and options lSrcs bazel.LabelListAttribute @@ -448,6 +510,8 @@ type compilerAttributes struct { suffix bazel.StringAttribute fdoProfile bazel.LabelAttribute + + additionalCompilerInputs bazel.LabelListAttribute } type filterOutFn func(string) bool @@ -494,14 +558,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,11 +629,14 @@ 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.protoSrcs.Append(partitionedSrcs[protoFromGenPartition]) ca.aidlSrcs = partitionedSrcs[aidlSrcPartition] for p, lla := range partitionedSrcs { @@ -580,10 +644,22 @@ func (ca *compilerAttributes) finalize(ctx android.BazelConversionPathContext, i if lla.IsEmpty() { continue } - lla.Append(implementationHdrs) + lla.Append(partitionedImplHdrs[hdrPartition]) partitionedSrcs[p] = lla } + ca.hdrs = partitionedHdrs[hdrPartition] + + ca.includesFromHeaders(ctx, partitionedImplHdrs[hdrPartition], partitionedHdrs[hdrPartition]) + + xsdSrcs := bazel.SubtractBazelLabelListAttribute(partitionedSrcs[xsdSrcPartition], partitionedHdrs[xsdSrcPartition]) + xsdSrcs.Append(partitionedImplHdrs[xsdSrcPartition]) + ca.exportXsdSrcs = partitionedHdrs[xsdSrcPartition] + ca.xsdSrcs = bazel.FirstUniqueBazelLabelListAttribute(xsdSrcs) + + ca.genruleHeaders = partitionedImplHdrs[genrulePartition] + ca.exportGenruleHeaders = partitionedHdrs[genrulePartition] + ca.srcs = partitionedSrcs[cppSrcPartition] ca.cSrcs = partitionedSrcs[cSrcPartition] ca.asSrcs = partitionedSrcs[asSrcPartition] @@ -604,11 +680,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 +696,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 +743,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 +787,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 +857,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 +876,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 +886,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 +902,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 +932,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 +949,17 @@ func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) (&compilerAttrs).convertProductVariables(ctx, productVariableProps) (&linkerAttrs).convertProductVariables(ctx, productVariableProps) - (&compilerAttrs).finalize(ctx, implementationHdrs) + (&compilerAttrs).finalize(ctx, implementationHdrs, exportHdrs) (&linkerAttrs).finalize(ctx) (&compilerAttrs.srcs).Add(bp2BuildYasm(ctx, module, compilerAttrs)) + (&linkerAttrs).deps.Append(compilerAttrs.exportGenruleHeaders) + (&linkerAttrs).implementationDeps.Append(compilerAttrs.genruleHeaders) + + (&linkerAttrs).wholeArchiveDeps.Append(compilerAttrs.exportXsdSrcs) + (&linkerAttrs).implementationWholeArchiveDeps.Append(compilerAttrs.xsdSrcs) + protoDep := bp2buildProto(ctx, module, compilerAttrs.protoSrcs) // bp2buildProto will only set wholeStaticLib or implementationWholeStaticLib, but we don't know @@ -925,13 +1020,25 @@ func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) (&compilerAttrs).localIncludes.Append(rsLocalIncludes) (&compilerAttrs).localIncludes.Value = android.FirstUniqueStrings(compilerAttrs.localIncludes.Value) - features := compilerAttrs.features.Clone().Append(linkerAttrs.features).Append(bp2buildSanitizerFeatures(ctx, module)) + sanitizerValues := bp2buildSanitizerFeatures(ctx, module) + + features := compilerAttrs.features.Clone().Append(linkerAttrs.features).Append(sanitizerValues.features) features = features.Append(bp2buildLtoFeatures(ctx, module)) features = features.Append(convertHiddenVisibilityToFeatureBase(ctx, module)) features.DeduplicateAxesFromBase() + compilerAttrs.copts = *compilerAttrs.copts.Append(sanitizerValues.copts) + compilerAttrs.additionalCompilerInputs = *compilerAttrs.additionalCompilerInputs.Append(sanitizerValues.additionalCompilerInputs) + addMuslSystemDynamicDeps(ctx, linkerAttrs) + // Dedupe all deps. + (&linkerAttrs).deps.Value = bazel.FirstUniqueBazelLabelList((&linkerAttrs).deps.Value) + (&linkerAttrs).implementationDeps.Value = bazel.FirstUniqueBazelLabelList((&linkerAttrs).implementationDeps.Value) + (&linkerAttrs).implementationDynamicDeps.Value = bazel.FirstUniqueBazelLabelList((&linkerAttrs).implementationDynamicDeps.Value) + (&linkerAttrs).wholeArchiveDeps.Value = bazel.FirstUniqueBazelLabelList((&linkerAttrs).wholeArchiveDeps.Value) + (&linkerAttrs).implementationWholeArchiveDeps.Value = bazel.FirstUniqueBazelLabelList((&linkerAttrs).implementationWholeArchiveDeps.Value) + return baseAttributes{ compilerAttrs, linkerAttrs, @@ -1139,6 +1246,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 +1309,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 +1353,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 +1746,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 +1855,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 { @@ -1804,8 +1926,16 @@ func bp2buildBinaryLinkerProps(ctx android.BazelConversionPathContext, m *Module return attrs } -func bp2buildSanitizerFeatures(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute { +type sanitizerValues struct { + features bazel.StringListAttribute + copts bazel.StringListAttribute + additionalCompilerInputs bazel.LabelListAttribute +} + +func bp2buildSanitizerFeatures(ctx android.BazelConversionPathContext, m *Module) sanitizerValues { sanitizerFeatures := bazel.StringListAttribute{} + sanitizerCopts := bazel.StringListAttribute{} + sanitizerCompilerInputs := bazel.LabelListAttribute{} bp2BuildPropParseHelper(ctx, m, &SanitizeProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { var features []string if sanitizerProps, ok := props.(*SanitizeProperties); ok { @@ -1817,9 +1947,10 @@ func bp2buildSanitizerFeatures(ctx android.BazelConversionPathContext, m *Module } blocklist := sanitizerProps.Sanitize.Blocklist 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) + // TODO: b/294868620 - Change this not to use the special axis when completing the bug + coptValue := fmt.Sprintf("-fsanitize-ignorelist=$(location %s)", *blocklist) + sanitizerCopts.SetSelectValue(bazel.SanitizersEnabledAxis, bazel.SanitizersEnabled, []string{coptValue}) + sanitizerCompilerInputs.SetSelectValue(bazel.SanitizersEnabledAxis, bazel.SanitizersEnabled, bazel.MakeLabelListFromTargetNames([]string{*blocklist})) } if sanitizerProps.Sanitize.Cfi != nil && !proptools.Bool(sanitizerProps.Sanitize.Cfi) { features = append(features, "-android_cfi") @@ -1832,7 +1963,11 @@ func bp2buildSanitizerFeatures(ctx android.BazelConversionPathContext, m *Module sanitizerFeatures.SetSelectValue(axis, config, features) } }) - return sanitizerFeatures + return sanitizerValues{ + features: sanitizerFeatures, + copts: sanitizerCopts, + additionalCompilerInputs: sanitizerCompilerInputs, + } } func bp2buildLtoFeatures(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute { @@ -42,6 +42,7 @@ import ( func init() { RegisterCCBuildComponents(android.InitRegistrationContext) + pctx.Import("android/soong/android") pctx.Import("android/soong/cc/config") } @@ -73,6 +74,9 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) { ctx.TopDown("afdo_deps", afdoDepsMutator) ctx.BottomUp("afdo", afdoMutator).Parallel() + ctx.TopDown("orderfile_deps", orderfileDepsMutator) + ctx.BottomUp("orderfile", orderfileMutator).Parallel() + ctx.TopDown("lto_deps", ltoDepsMutator) ctx.BottomUp("lto", ltoMutator).Parallel() @@ -525,6 +529,7 @@ type ModuleContextIntf interface { getVndkExtendsModuleName() string isAfdoCompile() bool isPgoCompile() bool + isOrderfileCompile() bool isCfi() bool isFuzzer() bool isNDKStubLibrary() bool @@ -568,6 +573,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 +873,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 @@ -865,6 +889,7 @@ type Module struct { lto *lto afdo *afdo pgo *pgo + orderfile *orderfile library libraryInterface @@ -1079,6 +1104,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 +1225,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()...) } @@ -1232,6 +1264,9 @@ func (c *Module) Init() android.Module { if c.pgo != nil { c.AddProperties(c.pgo.props()...) } + if c.orderfile != nil { + c.AddProperties(c.orderfile.props()...) + } for _, feature := range c.features { c.AddProperties(feature.props()...) } @@ -1365,9 +1400,16 @@ func (c *Module) isPgoCompile() bool { return false } +func (c *Module) isOrderfileCompile() bool { + if orderfile := c.orderfile; orderfile != nil { + return orderfile.Properties.OrderfileLoad + } + return false +} + 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 } @@ -1670,6 +1712,10 @@ func (ctx *moduleContextImpl) isPgoCompile() bool { return ctx.mod.isPgoCompile() } +func (ctx *moduleContextImpl) isOrderfileCompile() bool { + return ctx.mod.isOrderfileCompile() +} + func (ctx *moduleContextImpl) isCfi() bool { return ctx.mod.isCfi() } @@ -1779,6 +1825,7 @@ func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Mo module.lto = <o{} module.afdo = &afdo{} module.pgo = &pgo{} + module.orderfile = &orderfile{} return module } @@ -2144,6 +2191,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 +2224,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) } @@ -2185,6 +2254,9 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { if c.pgo != nil { flags = c.pgo.flags(ctx, flags) } + if c.orderfile != nil { + flags = c.orderfile.flags(ctx, flags) + } for _, feature := range c.features { flags = feature.flags(ctx, flags) } @@ -2215,6 +2287,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 +2378,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) } @@ -2320,6 +2399,9 @@ func (c *Module) begin(ctx BaseModuleContext) { if c.lto != nil { c.lto.begin(ctx) } + if c.orderfile != nil { + c.orderfile.begin(ctx) + } if c.pgo != nil { c.pgo.begin(ctx) } @@ -2337,6 +2419,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 +3030,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()) } @@ -4225,6 +4310,7 @@ func DefaultsFactory(props ...interface{}) android.Module { <OProperties{}, &AfdoProperties{}, &PgoProperties{}, + &OrderfileProperties{}, &android.ProtoProperties{}, // RustBindgenProperties is included here so that cc_defaults can be used for rust_bindgen modules. &RustBindgenClangProperties{}, diff --git a/cc/cc_test.go b/cc/cc_test.go index 7534db222..7ce0f3715 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -654,6 +654,7 @@ func TestVndkLibrariesTxtAndroidMk(t *testing.T) { config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("29") + config.TestProductVariables.KeepVndk = BoolPtr(true) ctx := testCcWithConfig(t, config) module := ctx.ModuleForTests("llndk.libraries.txt", "android_common") @@ -3261,7 +3262,7 @@ func TestLibDepAndroidMkExportInMixedBuilds(t *testing.T) { }, }, LabelToCcBinary: map[string]cquery.CcUnstrippedInfo{ - "//:test": cquery.CcUnstrippedInfo{ + "//:test__tf_internal": cquery.CcUnstrippedInfo{ CcAndroidMkInfo: tc.androidMkInfo, }, "//:binary": cquery.CcUnstrippedInfo{ diff --git a/cc/compiler.go b/cc/compiler.go index 16f4a6ec0..5bed8a72f 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -189,13 +189,13 @@ type BaseCompilerProperties struct { // build the recovery variant of the C/C++ module. Exclude_generated_sources []string } - Vendor_ramdisk struct { + Ramdisk, Vendor_ramdisk struct { // list of source files that should not be used to - // build the vendor ramdisk variant of the C/C++ module. + // build the ramdisk variants of the C/C++ module. Exclude_srcs []string `android:"path"` - // List of additional cflags that should be used to build the vendor ramdisk - // variant of the C/C++ module. + // List of additional cflags that should be used to build the ramdisk + // variants of the C/C++ module. Cflags []string } Platform struct { @@ -351,6 +351,7 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps CheckBadCompilerFlags(ctx, "vendor.cflags", compiler.Properties.Target.Vendor.Cflags) CheckBadCompilerFlags(ctx, "product.cflags", compiler.Properties.Target.Product.Cflags) CheckBadCompilerFlags(ctx, "recovery.cflags", compiler.Properties.Target.Recovery.Cflags) + CheckBadCompilerFlags(ctx, "ramdisk.cflags", compiler.Properties.Target.Ramdisk.Cflags) CheckBadCompilerFlags(ctx, "vendor_ramdisk.cflags", compiler.Properties.Target.Vendor_ramdisk.Cflags) CheckBadCompilerFlags(ctx, "platform.cflags", compiler.Properties.Target.Platform.Cflags) @@ -536,6 +537,9 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps if ctx.inVendorRamdisk() { flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Vendor_ramdisk.Cflags)...) } + if ctx.inRamdisk() { + flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Ramdisk.Cflags)...) + } if !ctx.useSdk() { flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Platform.Cflags)...) } diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go index ca2e05fc3..12722a7de 100644 --- a/cc/config/arm64_device.go +++ b/cc/config/arm64_device.go @@ -100,7 +100,15 @@ func init() { return strings.Join(flags, " ") }) - exportedVars.ExportStringListStaticVariable("Arm64Cflags", arm64Cflags) + exportedVars.ExportStringList("Arm64Cflags", arm64Cflags) + pctx.VariableFunc("Arm64Cflags", func(ctx android.PackageVarContext) string { + flags := arm64Cflags + if ctx.Config().PageSizeAgnostic() { + flags = append(flags, "-D__BIONIC_NO_PAGE_SIZE_MACRO") + } + return strings.Join(flags, " ") + }) + exportedVars.ExportStringListStaticVariable("Arm64Cppflags", arm64Cppflags) exportedVars.ExportVariableReferenceDict("Arm64ArchVariantCflags", arm64ArchVariantCflagsVar) diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go index dec2b4552..3d6890cf0 100644 --- a/cc/config/arm_device.go +++ b/cc/config/arm_device.go @@ -43,9 +43,7 @@ var ( armNoFixCortexA8LdFlags = []string{"-Wl,--no-fix-cortex-a8"} - armArmCflags = []string{ - "-fstrict-aliasing", - } + armArmCflags = []string{} armThumbCflags = []string{ "-mthumb", @@ -185,12 +183,7 @@ func init() { exportedVars.ExportString("ArmClangTriple", clangTriple) exportedVars.ExportStringListStaticVariable("ArmLdflags", armLdflags) - exportedVars.ExportStringList("ArmLldflags", armLldflags) - pctx.VariableFunc("ArmLldflags", func(ctx android.PackageVarContext) string { - maxPageSizeFlag := "-Wl,-z,max-page-size=" + ctx.Config().MaxPageSizeSupported() - flags := append(armLldflags, maxPageSizeFlag) - return strings.Join(flags, " ") - }) + exportedVars.ExportStringListStaticVariable("ArmLldflags", armLldflags) exportedVars.ExportStringListStaticVariable("ArmFixCortexA8LdFlags", armFixCortexA8LdFlags) exportedVars.ExportStringListStaticVariable("ArmNoFixCortexA8LdFlags", armNoFixCortexA8LdFlags) diff --git a/cc/config/global.go b/cc/config/global.go index e450ba7ba..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{} @@ -147,6 +149,7 @@ var ( commonGlobalLldflags = []string{ "-fuse-ld=lld", "-Wl,--icf=safe", + "-Wl,--no-demangle", } deviceGlobalCppflags = []string{ @@ -305,7 +308,7 @@ var ( // prebuilts/clang default settings. ClangDefaultBase = "prebuilts/clang/host" - ClangDefaultVersion = "clang-r487747c" + ClangDefaultVersion = "clang-r498229" ClangDefaultShortVersion = "17" // Directories with warnings from Android.bp files. @@ -374,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/coverage.go b/cc/coverage.go index c0f697398..cbd8a6f3e 100644 --- a/cc/coverage.go +++ b/cc/coverage.go @@ -48,6 +48,7 @@ func (cov *coverage) props() []interface{} { func getGcovProfileLibraryName(ctx ModuleContextIntf) string { // This function should only ever be called for a cc.Module, so the // following statement should always succeed. + // LINT.IfChange if ctx.useSdk() { return "libprofile-extras_ndk" } else { @@ -63,6 +64,7 @@ func getClangProfileLibraryName(ctx ModuleContextIntf) string { } else { return "libprofile-clang-extras" } + // LINT.ThenChange(library.go) } func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps { diff --git a/cc/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/image.go b/cc/image.go index e65a9aadb..f91762adc 100644 --- a/cc/image.go +++ b/cc/image.go @@ -678,10 +678,17 @@ func squashVendorRamdiskSrcs(m *Module) { } } +func squashRamdiskSrcs(m *Module) { + if lib, ok := m.compiler.(*libraryDecorator); ok { + lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs, lib.baseCompiler.Properties.Target.Ramdisk.Exclude_srcs...) + } +} + func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) { m := module.(*Module) if variant == android.RamdiskVariation { m.MakeAsPlatform() + squashRamdiskSrcs(m) } else if variant == android.VendorRamdiskVariation { m.MakeAsPlatform() squashVendorRamdiskSrcs(m) diff --git a/cc/library.go b/cc/library.go index aec6433d8..2d4d60440 100644 --- a/cc/library.go +++ b/cc/library.go @@ -32,6 +32,20 @@ import ( "github.com/google/blueprint/proptools" ) +var ( + alwaysLinkLibraries = map[string]bool{ + // Coverage libraries are _always_ added as a whole_static_dep. By converting as these as + // alwayslink = True, we can add these as to deps (e.g. as a regular static dep) in Bazel + // without any extra complications in cc_shared_library roots to prevent linking the same + // library repeatedly. + "libprofile-extras_ndk": true, + "libprofile-extras": true, + "libprofile-clang-extras_ndk": true, + "libprofile-clang-extras_cfi_support": true, + "libprofile-clang-extras": true, + } +) + // LibraryProperties is a collection of properties shared by cc library rules/cc. type LibraryProperties struct { // local file name to pass to the linker as -unexported_symbols_list @@ -335,6 +349,7 @@ func libraryBp2Build(ctx android.TopDownMutatorContext, m *Module) { Runtime_deps: linkerAttrs.runtimeDeps, sdkAttributes: bp2BuildParseSdkAttributes(m), Native_coverage: baseAttributes.Native_coverage, + Additional_compiler_inputs: compilerAttrs.additionalCompilerInputs, } includeAttrs := includesAttributes{ @@ -362,6 +377,7 @@ func libraryBp2Build(ctx android.TopDownMutatorContext, m *Module) { Runtime_deps: linkerAttrs.runtimeDeps, sdkAttributes: bp2BuildParseSdkAttributes(m), Native_coverage: baseAttributes.Native_coverage, + Additional_compiler_inputs: compilerAttrs.additionalCompilerInputs, } staticTargetAttrs := &bazelCcLibraryStaticAttributes{ @@ -435,6 +451,10 @@ func libraryBp2Build(ctx android.TopDownMutatorContext, m *Module) { Bzl_load_location: "//build/bazel/rules/cc:cc_library_shared.bzl", } + if _, ok := alwaysLinkLibraries[m.Name()]; ok { + staticTargetAttrs.Alwayslink = proptools.BoolPtr(true) + } + var tagsForStaticVariant bazel.StringListAttribute if compilerAttrs.stubsSymbolFile == nil && len(compilerAttrs.stubsVersions.Value) == 0 { tagsForStaticVariant = android.ApexAvailableTagsWithoutTestApexes(ctx, m) @@ -1963,6 +1983,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 +2295,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() { @@ -2940,6 +2964,7 @@ func sharedOrStaticLibraryBp2Build(ctx android.TopDownMutatorContext, module *Mo sdkAttributes: bp2BuildParseSdkAttributes(module), Runtime_deps: linkerAttrs.runtimeDeps, Native_coverage: baseAttributes.Native_coverage, + Additional_compiler_inputs: compilerAttrs.additionalCompilerInputs, } module.convertTidyAttributes(ctx, &commonAttrs.tidyAttributes) @@ -2947,6 +2972,10 @@ func sharedOrStaticLibraryBp2Build(ctx android.TopDownMutatorContext, module *Mo var attrs interface{} if isStatic { commonAttrs.Deps.Add(baseAttributes.protoDependency) + var alwayslink *bool + if _, ok := alwaysLinkLibraries[module.Name()]; ok && isStatic { + alwayslink = proptools.BoolPtr(true) + } attrs = &bazelCcLibraryStaticAttributes{ staticOrSharedAttributes: commonAttrs, Rtti: compilerAttrs.rtti, @@ -2960,8 +2989,10 @@ func sharedOrStaticLibraryBp2Build(ctx android.TopDownMutatorContext, module *Mo Conlyflags: compilerAttrs.conlyFlags, Asflags: asFlags, - Features: *features, + Alwayslink: alwayslink, + Features: *features, } + } else { commonAttrs.Dynamic_deps.Add(baseAttributes.protoDependency) @@ -3043,7 +3074,8 @@ type bazelCcLibraryStaticAttributes struct { Conlyflags bazel.StringListAttribute Asflags bazel.StringListAttribute - Features bazel.StringListAttribute + Alwayslink *bool + Features bazel.StringListAttribute } // TODO(b/199902614): Can this be factored to share with the other Attributes? 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() { @@ -104,10 +135,14 @@ func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags { ltoLdFlags = append(ltoLdFlags, cachePolicyFormat+policy) } - // If the module does not have a profile, be conservative and limit cross TU inline - // limit to 5 LLVM IR instructions, to balance binary size increase and performance. - if !ctx.Darwin() && !ctx.isPgoCompile() && !ctx.isAfdoCompile() { - ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=5") + // Reduce the inlining threshold for a better balance of binary size and + // performance. + if !ctx.Darwin() { + if ctx.isPgoCompile() || ctx.isAfdoCompile() { + ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=40") + } else { + ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=5") + } } flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlags...) @@ -118,34 +153,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) } @@ -160,10 +167,8 @@ func GlobalThinLTO(ctx android.BaseModuleContext) bool { // 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 +243,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_library.go b/cc/ndk_library.go index f0b7cc52b..9281aebb5 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -31,9 +31,8 @@ import ( func init() { pctx.HostBinToolVariable("ndkStubGenerator", "ndkstubgen") - pctx.HostBinToolVariable("abidiff", "abidiff") - pctx.HostBinToolVariable("abitidy", "abitidy") - pctx.HostBinToolVariable("abidw", "abidw") + pctx.HostBinToolVariable("stg", "stg") + pctx.HostBinToolVariable("stgdiff", "stgdiff") } var ( @@ -44,28 +43,20 @@ var ( CommandDeps: []string{"$ndkStubGenerator"}, }, "arch", "apiLevel", "apiMap", "flags") - abidw = pctx.AndroidStaticRule("abidw", + stg = pctx.AndroidStaticRule("stg", blueprint.RuleParams{ - Command: "$abidw --type-id-style hash --no-corpus-path " + - "--no-show-locs --no-comp-dir-path -w $symbolList " + - "$in --out-file $out", - CommandDeps: []string{"$abidw"}, + Command: "$stg -S :$symbolList --elf $in -o $out", + CommandDeps: []string{"$stg"}, }, "symbolList") - abitidy = pctx.AndroidStaticRule("abitidy", - blueprint.RuleParams{ - Command: "$abitidy --all $flags -i $in -o $out", - CommandDeps: []string{"$abitidy"}, - }, "flags") - - abidiff = pctx.AndroidStaticRule("abidiff", + stgdiff = pctx.AndroidStaticRule("stgdiff", blueprint.RuleParams{ // Need to create *some* output for ninja. We don't want to use tee // because we don't want to spam the build output with "nothing // changed" messages, so redirect output message to $out, and if // changes were detected print the output and fail. - Command: "$abidiff $args $in > $out || (cat $out && false)", - CommandDeps: []string{"$abidiff"}, + Command: "$stgdiff $args --stg $in -o $out || (cat $out && false)", + CommandDeps: []string{"$stgdiff"}, }, "args") ndkLibrarySuffix = ".ndk" @@ -107,12 +98,6 @@ type libraryProperties struct { // https://github.com/android-ndk/ndk/issues/265. Unversioned_until *string - // If true, does not emit errors when APIs lacking type information are - // found. This is false by default and should not be enabled outside bionic, - // where it is enabled pending a fix for http://b/190554910 (no debug info - // for asm implemented symbols). - Allow_untyped_symbols *bool - // Headers presented by this library to the Public API Surface Export_header_libs []string } @@ -326,7 +311,7 @@ func (this *stubDecorator) findPrebuiltAbiDump(ctx ModuleContext, apiLevel android.ApiLevel) android.OptionalPath { subpath := filepath.Join("prebuilts/abi-dumps/ndk", apiLevel.String(), - ctx.Arch().ArchType.String(), this.libraryName(ctx), "abi.xml") + ctx.Arch().ArchType.String(), this.libraryName(ctx), "abi.stg") return android.ExistentPathForSource(ctx, subpath) } @@ -359,34 +344,17 @@ func canDiffAbi() bool { func (this *stubDecorator) dumpAbi(ctx ModuleContext, symbolList android.Path) { implementationLibrary := this.findImplementationLibrary(ctx) - abiRawPath := getNdkAbiDumpInstallBase(ctx).Join(ctx, + this.abiDumpPath = getNdkAbiDumpInstallBase(ctx).Join(ctx, this.apiLevel.String(), ctx.Arch().ArchType.String(), - this.libraryName(ctx), "abi.raw.xml") + this.libraryName(ctx), "abi.stg") ctx.Build(pctx, android.BuildParams{ - Rule: abidw, - Description: fmt.Sprintf("abidw %s", implementationLibrary), + Rule: stg, + Description: fmt.Sprintf("stg %s", implementationLibrary), Input: implementationLibrary, - Output: abiRawPath, Implicit: symbolList, - Args: map[string]string{ - "symbolList": symbolList.String(), - }, - }) - - this.abiDumpPath = getNdkAbiDumpInstallBase(ctx).Join(ctx, - this.apiLevel.String(), ctx.Arch().ArchType.String(), - this.libraryName(ctx), "abi.xml") - untypedFlag := "--abort-on-untyped-symbols" - if proptools.BoolDefault(this.properties.Allow_untyped_symbols, false) { - untypedFlag = "" - } - ctx.Build(pctx, android.BuildParams{ - Rule: abitidy, - Description: fmt.Sprintf("abitidy %s", implementationLibrary), - Input: abiRawPath, Output: this.abiDumpPath, Args: map[string]string{ - "flags": untypedFlag, + "symbolList": symbolList.String(), }, }) } @@ -405,7 +373,7 @@ func findNextApiLevel(ctx ModuleContext, apiLevel android.ApiLevel) *android.Api func (this *stubDecorator) diffAbi(ctx ModuleContext) { // Catch any ABI changes compared to the checked-in definition of this API // level. - abiDiffPath := android.PathForModuleOut(ctx, "abidiff.timestamp") + abiDiffPath := android.PathForModuleOut(ctx, "stgdiff.timestamp") prebuiltAbiDump := this.findPrebuiltAbiDump(ctx, this.apiLevel) missingPrebuiltError := fmt.Sprintf( "Did not find prebuilt ABI dump for %q (%q). Generate with "+ @@ -421,11 +389,14 @@ func (this *stubDecorator) diffAbi(ctx ModuleContext) { }) } else { ctx.Build(pctx, android.BuildParams{ - Rule: abidiff, - Description: fmt.Sprintf("abidiff %s %s", prebuiltAbiDump, + Rule: stgdiff, + Description: fmt.Sprintf("Comparing ABI %s %s", prebuiltAbiDump, this.abiDumpPath), Output: abiDiffPath, Inputs: android.Paths{prebuiltAbiDump.Path(), this.abiDumpPath}, + Args: map[string]string{ + "args": "--format=small", + }, }) } this.abiDiffPaths = append(this.abiDiffPaths, abiDiffPath) @@ -452,13 +423,13 @@ func (this *stubDecorator) diffAbi(ctx ModuleContext) { }) } else { ctx.Build(pctx, android.BuildParams{ - Rule: abidiff, + Rule: stgdiff, Description: fmt.Sprintf("abidiff %s %s", this.abiDumpPath, nextAbiDump), Output: nextAbiDiffPath, Inputs: android.Paths{this.abiDumpPath, nextAbiDump.Path()}, Args: map[string]string{ - "args": "--no-added-syms", + "args": "--format=small --ignore=interface_addition", }, }) } diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go index 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/orderfile.go b/cc/orderfile.go new file mode 100644 index 000000000..b64c1c7a1 --- /dev/null +++ b/cc/orderfile.go @@ -0,0 +1,256 @@ +// 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. +// +// Note: If you want to know how to use orderfile for your binary or shared +// library, you can go look at the README in toolchains/pgo-profiles/orderfiles + +package cc + +import ( + "fmt" + + "android/soong/android" +) + +// Order files are text files containing symbols representing functions names. +// Linkers (lld) uses order files to layout functions in a specific order. +// These binaries with ordered symbols will reduce page faults and improve a program's launch time +// due to the efficient loading of symbols during a program’s cold-start. +var ( + // Add flags to ignore warnings about symbols not be found + // or not allowed to be ordered + orderfileOtherFlags = []string{ + "-Wl,--no-warn-symbol-ordering", + } + + // Add folder projects for orderfiles + globalOrderfileProjects = []string{ + "toolchain/pgo-profiles/orderfiles", + "vendor/google_data/pgo_profile/orderfiles", + } +) + +var orderfileProjectsConfigKey = android.NewOnceKey("OrderfileProjects") + +const orderfileProfileFlag = "-forder-file-instrumentation" +const orderfileUseFormat = "-Wl,--symbol-ordering-file=%s" + +func getOrderfileProjects(config android.DeviceConfig) []string { + return config.OnceStringSlice(orderfileProjectsConfigKey, func() []string { + return globalOrderfileProjects + }) +} + +func recordMissingOrderfile(ctx BaseModuleContext, missing string) { + getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true) +} + +type OrderfileProperties struct { + Orderfile struct { + Instrumentation *bool + Order_file_path *string `android:"arch_variant"` + Load_order_file *bool `android:"arch_variant"` + // Additional compiler flags to use when building this module + // for orderfile profiling. + Cflags []string `android:"arch_variant"` + } `android:"arch_variant"` + + ShouldProfileModule bool `blueprint:"mutated"` + OrderfileLoad bool `blueprint:"mutated"` + OrderfileInstrLink bool `blueprint:"mutated"` +} + +type orderfile struct { + Properties OrderfileProperties +} + +func (props *OrderfileProperties) shouldInstrument() bool { + return Bool(props.Orderfile.Instrumentation) +} + +// ShouldLoadOrderfile returns true if we need to load the order file rather than +// profile the binary or shared library +func (props *OrderfileProperties) shouldLoadOrderfile() bool { + return Bool(props.Orderfile.Load_order_file) && props.Orderfile.Order_file_path != nil +} + +// orderfileEnabled returns true for binaries and shared libraries +// if instrument flag is set to true +func (orderfile *orderfile) orderfileEnabled() bool { + return orderfile != nil && orderfile.Properties.shouldInstrument() +} + +// orderfileLinkEnabled returns true for binaries and shared libraries +// if you should instrument dependencies +func (orderfile *orderfile) orderfileLinkEnabled() bool { + return orderfile != nil && orderfile.Properties.OrderfileInstrLink +} + +func (orderfile *orderfile) props() []interface{} { + return []interface{}{&orderfile.Properties} +} + +// Get the path to the order file by checking it is valid and not empty +func (props *OrderfileProperties) getOrderfile(ctx BaseModuleContext) android.OptionalPath { + orderFile := *props.Orderfile.Order_file_path + + // Test if the order file is present in any of the Orderfile projects + for _, profileProject := range getOrderfileProjects(ctx.DeviceConfig()) { + path := android.ExistentPathForSource(ctx, profileProject, orderFile) + if path.Valid() { + return path + } + } + + // Record that this module's order file is absent + missing := *props.Orderfile.Order_file_path + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName() + recordMissingOrderfile(ctx, missing) + + return android.OptionalPath{} +} + +func (props *OrderfileProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags { + flags.Local.CFlags = append(flags.Local.CFlags, orderfileProfileFlag) + flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm -enable-order-file-instrumentation") + flags.Local.CFlags = append(flags.Local.CFlags, props.Orderfile.Cflags...) + flags.Local.LdFlags = append(flags.Local.LdFlags, orderfileProfileFlag) + return flags +} + + +func (props *OrderfileProperties) loadOrderfileFlags(ctx ModuleContext, file string) []string { + flags := []string{fmt.Sprintf(orderfileUseFormat, file)} + flags = append(flags, orderfileOtherFlags...) + return flags +} + +func (props *OrderfileProperties) addLoadFlags(ctx ModuleContext, flags Flags) Flags { + orderFile := props.getOrderfile(ctx) + orderFilePath := orderFile.Path() + loadFlags := props.loadOrderfileFlags(ctx, orderFilePath.String()) + + flags.Local.LdFlags = append(flags.Local.LdFlags, loadFlags...) + + // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt + // if orderfile gets updated + flags.CFlagsDeps = append(flags.CFlagsDeps, orderFilePath) + flags.LdFlagsDeps = append(flags.LdFlagsDeps, orderFilePath) + return flags +} + +func (orderfile *orderfile) begin(ctx BaseModuleContext) { + // Currently, we are not enabling orderfiles for host + if ctx.Host() { + return + } + + // Currently, we are not enabling orderfiles to begin from static libraries + if ctx.static() && !ctx.staticBinary() { + return + } + + if ctx.DeviceConfig().ClangCoverageEnabled() { + return + } + + // Checking if orderfile is enabled for this module + if !orderfile.orderfileEnabled() { + return + } + + orderfile.Properties.OrderfileLoad = orderfile.Properties.shouldLoadOrderfile() + orderfile.Properties.ShouldProfileModule = !orderfile.Properties.shouldLoadOrderfile() + orderfile.Properties.OrderfileInstrLink = orderfile.orderfileEnabled() && !orderfile.Properties.shouldLoadOrderfile() +} + +func (orderfile *orderfile) flags(ctx ModuleContext, flags Flags) Flags { + props := orderfile.Properties + // Add flags to load the orderfile using the path in its Android.bp + if orderfile.Properties.OrderfileLoad { + flags = props.addLoadFlags(ctx, flags) + return flags + } + + // Add flags to profile this module + if props.ShouldProfileModule { + flags = props.addInstrumentationProfileGatherFlags(ctx, flags) + return flags + } + + return flags +} + +// Propagate profile orderfile flags down from binaries and shared libraries +// We do not allow propagation for load flags because the orderfile is specific +// to the module (binary / shared library) +func orderfileDepsMutator(mctx android.TopDownMutatorContext) { + if m, ok := mctx.Module().(*Module); ok { + if !m.orderfile.orderfileLinkEnabled() { + return + } + mctx.WalkDeps(func(dep android. + Module, parent android.Module) bool { + tag := mctx.OtherModuleDependencyTag(dep) + libTag, isLibTag := tag.(libraryDependencyTag) + + // Do not recurse down non-static dependencies + if isLibTag { + if !libTag.static() { + return false + } + } else { + if tag != objDepTag && tag != reuseObjTag { + return false + } + } + + if dep, ok := dep.(*Module); ok { + if m.orderfile.Properties.OrderfileInstrLink { + dep.orderfile.Properties.OrderfileInstrLink = true; + } + } + + return true + }) + } +} + +// Create orderfile variants for modules that need them +func orderfileMutator(mctx android.BottomUpMutatorContext) { + if m, ok := mctx.Module().(*Module); ok && m.orderfile != nil { + if !m.static() && m.orderfile.orderfileEnabled() { + mctx.SetDependencyVariation("orderfile") + return + } + + variationNames := []string{""} + if m.orderfile.Properties.OrderfileInstrLink { + variationNames = append(variationNames, "orderfile") + } + + if len(variationNames) > 1 { + modules := mctx.CreateVariations(variationNames...) + for i, name := range variationNames { + if name == "" { + continue + } + variation := modules[i].(*Module) + variation.Properties.PreventInstall = true + variation.Properties.HideFromMake = true + variation.orderfile.Properties.ShouldProfileModule = true + variation.orderfile.Properties.OrderfileLoad = false + } + } + } +} diff --git a/cc/orderfile_test.go b/cc/orderfile_test.go new file mode 100644 index 000000000..f68457d32 --- /dev/null +++ b/cc/orderfile_test.go @@ -0,0 +1,470 @@ +// 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 ( + "testing" + "strings" + + "android/soong/android" +) + +func TestOrderfileProfileSharedLibrary(t *testing.T) { + t.Parallel() + bp := ` + cc_library_shared { + name: "libTest", + srcs: ["test.c"], + orderfile : { + instrumentation: true, + load_order_file: false, + order_file_path: "", + }, + } + ` + + result := android.GroupFixturePreparers( + prepareForCcTest, + ).RunTestWithBp(t, bp) + + expectedCFlag := "-forder-file-instrumentation" + + libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") + + // Check cFlags of orderfile-enabled module + cFlags := libTest.Rule("cc").Args["cFlags"] + if !strings.Contains(cFlags, expectedCFlag) { + t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags) + } + + // Check ldFlags of orderfile-enabled module + ldFlags := libTest.Rule("ld").Args["ldFlags"] + if !strings.Contains(ldFlags, expectedCFlag) { + t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags) + } +} + +func TestOrderfileLoadSharedLibrary(t *testing.T) { + t.Parallel() + bp := ` + cc_library_shared { + name: "libTest", + srcs: ["test.c"], + orderfile : { + instrumentation: true, + load_order_file: true, + order_file_path: "libTest.orderfile", + }, + } + ` + + result := android.GroupFixturePreparers( + prepareForCcTest, + android.FixtureAddTextFile("toolchain/pgo-profiles/orderfiles/libTest.orderfile", "TEST"), + ).RunTestWithBp(t, bp) + + expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/libTest.orderfile" + + libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") + + // Check ldFlags of orderfile-enabled module + ldFlags := libTest.Rule("ld").Args["ldFlags"] + if !strings.Contains(ldFlags, expectedCFlag) { + t.Errorf("Expected 'libTest' to load orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags) + } +} + +func TestOrderfileProfileBinary(t *testing.T) { + t.Parallel() + bp := ` + cc_binary { + name: "test", + srcs: ["test.c"], + orderfile : { + instrumentation: true, + load_order_file: false, + order_file_path: "", + }, + } + ` + + result := android.GroupFixturePreparers( + prepareForCcTest, + ).RunTestWithBp(t, bp) + + expectedCFlag := "-forder-file-instrumentation" + + test := result.ModuleForTests("test", "android_arm64_armv8-a") + + // Check cFlags of orderfile-enabled module + cFlags := test.Rule("cc").Args["cFlags"] + if !strings.Contains(cFlags, expectedCFlag) { + t.Errorf("Expected 'test' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags) + } + + // Check ldFlags of orderfile-enabled module + ldFlags := test.Rule("ld").Args["ldFlags"] + if !strings.Contains(ldFlags, expectedCFlag) { + t.Errorf("Expected 'test' to enable orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags) + } +} + +func TestOrderfileLoadBinary(t *testing.T) { + t.Parallel() + bp := ` + cc_binary { + name: "test", + srcs: ["test.c"], + orderfile : { + instrumentation: true, + load_order_file: true, + order_file_path: "test.orderfile", + }, + } + ` + + result := android.GroupFixturePreparers( + prepareForCcTest, + android.FixtureAddTextFile("toolchain/pgo-profiles/orderfiles/test.orderfile", "TEST"), + ).RunTestWithBp(t, bp) + + expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/test.orderfile" + + test := result.ModuleForTests("test", "android_arm64_armv8-a") + + // Check ldFlags of orderfile-enabled module + ldFlags := test.Rule("ld").Args["ldFlags"] + if !strings.Contains(ldFlags, expectedCFlag) { + t.Errorf("Expected 'test' to load orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags) + } +} + +// Profile flags should propagate through static libraries +func TestOrderfileProfilePropagateStaticDeps(t *testing.T) { + t.Parallel() + bp := ` + cc_library_shared { + name: "libTest", + srcs: ["test.c"], + static_libs: ["libFoo"], + orderfile : { + instrumentation: true, + load_order_file: false, + order_file_path: "", + }, + } + + cc_library_static { + name: "libFoo", + srcs: ["foo.c"], + static_libs: ["libBar"], + } + + cc_library_static { + name: "libBar", + srcs: ["bar.c"], + } + ` + + result := android.GroupFixturePreparers( + prepareForCcTest, + ).RunTestWithBp(t, bp) + + expectedCFlag := "-forder-file-instrumentation" + + // Check cFlags of orderfile-enabled module + libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") + + cFlags := libTest.Rule("cc").Args["cFlags"] + if !strings.Contains(cFlags, expectedCFlag) { + t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags) + } + + // Check cFlags of orderfile variant static libraries + libFooOfVariant := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_orderfile") + libBarOfVariant := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_orderfile") + + cFlags = libFooOfVariant.Rule("cc").Args["cFlags"] + if !strings.Contains(cFlags, expectedCFlag) { + t.Errorf("Expected 'libFooOfVariant' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags) + } + + cFlags = libBarOfVariant.Rule("cc").Args["cFlags"] + if !strings.Contains(cFlags, expectedCFlag) { + t.Errorf("Expected 'libBarOfVariant' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags) + } + + // Check dependency edge from orderfile-enabled module to orderfile variant static libraries + if !hasDirectDep(result, libTest.Module(), libFooOfVariant.Module()) { + t.Errorf("libTest missing dependency on orderfile variant of libFoo") + } + + if !hasDirectDep(result, libFooOfVariant.Module(), libBarOfVariant.Module()) { + t.Errorf("libTest missing dependency on orderfile variant of libBar") + } + + // Check cFlags of the non-orderfile variant static libraries + libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static") + libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static") + + cFlags = libFoo.Rule("cc").Args["cFlags"] + if strings.Contains(cFlags, expectedCFlag) { + t.Errorf("Expected 'libFoo' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags) + } + + cFlags = libBar.Rule("cc").Args["cFlags"] + if strings.Contains(cFlags, expectedCFlag) { + t.Errorf("Expected 'libBar' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags) + } + + // Check no dependency edge from orderfile-enabled module to non-orderfile variant static libraries + if hasDirectDep(result, libTest.Module(), libFoo.Module()) { + t.Errorf("libTest has dependency on non-orderfile variant of libFoo") + } + + if !hasDirectDep(result, libFoo.Module(), libBar.Module()) { + t.Errorf("libTest has dependency on non-orderfile variant of libBar") + } +} + +// Load flags should never propagate +func TestOrderfileLoadPropagateStaticDeps(t *testing.T) { + t.Parallel() + bp := ` + cc_library_shared { + name: "libTest", + srcs: ["test.c"], + static_libs: ["libFoo"], + orderfile : { + instrumentation: true, + load_order_file: true, + order_file_path: "test.orderfile", + }, + } + + cc_library_static { + name: "libFoo", + srcs: ["foo.c"], + static_libs: ["libBar"], + } + + cc_library_static { + name: "libBar", + srcs: ["bar.c"], + } + ` + + result := android.GroupFixturePreparers( + prepareForCcTest, + android.FixtureAddTextFile("toolchain/pgo-profiles/orderfiles/test.orderfile", "TEST"), + ).RunTestWithBp(t, bp) + + expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/test.orderfile" + + // Check ldFlags of orderfile-enabled module + libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") + + ldFlags := libTest.Rule("ld").Args["ldFlags"] + if !strings.Contains(ldFlags, expectedCFlag) { + t.Errorf("Expected 'libTest' to load orderfile, but did not find %q in ldFlags %q", expectedCFlag, ldFlags) + } + + libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static") + libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static") + + // Check dependency edge from orderfile-enabled module to non-orderfile variant static libraries + if !hasDirectDep(result, libTest.Module(), libFoo.Module()) { + t.Errorf("libTest missing dependency on non-orderfile variant of libFoo") + } + + if !hasDirectDep(result, libFoo.Module(), libBar.Module()) { + t.Errorf("libTest missing dependency on non-orderfile variant of libBar") + } + + // Make sure no orderfile variants are created for static libraries because the flags were not propagated + libFooVariants := result.ModuleVariantsForTests("libFoo") + for _, v := range libFooVariants { + if strings.Contains(v, "orderfile") { + t.Errorf("Expected variants for 'libFoo' to not contain 'orderfile', but found %q", v) + } + } + + libBarVariants := result.ModuleVariantsForTests("libBar") + for _, v := range libBarVariants { + if strings.Contains(v, "orderfile") { + t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v) + } + } +} + +// Profile flags should not propagate through shared libraries +func TestOrderfileProfilePropagateSharedDeps(t *testing.T) { + t.Parallel() + bp := ` + cc_library_shared { + name: "libTest", + srcs: ["test.c"], + shared_libs: ["libFoo"], + orderfile : { + instrumentation: true, + load_order_file: false, + order_file_path: "", + }, + } + + cc_library_shared { + name: "libFoo", + srcs: ["foo.c"], + static_libs: ["libBar"], + } + + cc_library_static { + name: "libBar", + srcs: ["bar.c"], + } + ` + + result := android.GroupFixturePreparers( + prepareForCcTest, + ).RunTestWithBp(t, bp) + + expectedCFlag := "-forder-file-instrumentation" + + // Check cFlags of orderfile-enabled module + libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") + + cFlags := libTest.Rule("cc").Args["cFlags"] + if !strings.Contains(cFlags, expectedCFlag) { + t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags) + } + + // Check cFlags of the static and shared libraries + libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_shared") + libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static") + + cFlags = libFoo.Rule("cc").Args["cFlags"] + if strings.Contains(cFlags, expectedCFlag) { + t.Errorf("Expected 'libFoo' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags) + } + + cFlags = libBar.Rule("cc").Args["cFlags"] + if strings.Contains(cFlags, expectedCFlag) { + t.Errorf("Expected 'libBar' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags) + } + + // Check dependency edge from orderfile-enabled module to non-orderfile variant static libraries + if !hasDirectDep(result, libTest.Module(), libFoo.Module()) { + t.Errorf("libTest missing dependency on non-orderfile variant of libFoo") + } + + if !hasDirectDep(result, libFoo.Module(), libBar.Module()) { + t.Errorf("libTest missing dependency on non-orderfile variant of libBar") + } + + // Make sure no orderfile variants are created for libraries because the flags were not propagated + libFooVariants := result.ModuleVariantsForTests("libFoo") + for _, v := range libFooVariants { + if strings.Contains(v, "orderfile") { + t.Errorf("Expected variants for 'libFoo' to not contain 'orderfile', but found %q", v) + } + } + + libBarVariants := result.ModuleVariantsForTests("libBar") + for _, v := range libBarVariants { + if strings.Contains(v, "orderfile") { + t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v) + } + } +} + +// Profile flags should not work or be propagated if orderfile flags start at a static library +func TestOrderfileProfileStaticLibrary(t *testing.T) { + t.Parallel() + bp := ` + cc_library_static { + name: "libTest", + srcs: ["test.c"], + static_libs: ["libFoo"], + orderfile : { + instrumentation: true, + load_order_file: false, + order_file_path: "", + }, + } + + cc_library_static { + name: "libFoo", + srcs: ["foo.c"], + static_libs: ["libBar"], + } + + cc_library_static { + name: "libBar", + srcs: ["bar.c"], + } + ` + + result := android.GroupFixturePreparers( + prepareForCcTest, + ).RunTestWithBp(t, bp) + + expectedCFlag := "-forder-file-instrumentation" + + // Check cFlags of module + libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_static") + + cFlags := libTest.Rule("cc").Args["cFlags"] + if strings.Contains(cFlags, expectedCFlag) { + t.Errorf("Expected 'libTest' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags) + } + + // Check cFlags of the static libraries + libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static") + libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static") + + cFlags = libFoo.Rule("cc").Args["cFlags"] + if strings.Contains(cFlags, expectedCFlag) { + t.Errorf("Expected 'libFoo' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags) + } + + cFlags = libBar.Rule("cc").Args["cFlags"] + if strings.Contains(cFlags, expectedCFlag) { + t.Errorf("Expected 'libBar' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags) + } + + // Check dependency edge from orderfile-enabled module to non-orderfile variant libraries + if !hasDirectDep(result, libTest.Module(), libFoo.Module()) { + t.Errorf("libTest missing dependency on non-orderfile variant of libFoo") + } + + if !hasDirectDep(result, libFoo.Module(), libBar.Module()) { + t.Errorf("libTest missing dependency on non-orderfile variant of libBar") + } + + // Make sure no orderfile variants are created for static libraries because the flags were not propagated + libFooVariants := result.ModuleVariantsForTests("libFoo") + for _, v := range libFooVariants { + if strings.Contains(v, "orderfile") { + t.Errorf("Expected variants for 'libFoo' to not contain 'orderfile', but found %q", v) + } + } + + libBarVariants := result.ModuleVariantsForTests("libBar") + for _, v := range libBarVariants { + if strings.Contains(v, "orderfile") { + t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v) + } + } +}
\ No newline at end of file @@ -101,11 +101,12 @@ func rsGenerateCpp(ctx android.ModuleContext, rsFiles android.Paths, rsFlags str func rsFlags(ctx ModuleContext, flags Flags, properties *BaseCompilerProperties) Flags { targetApi := String(properties.Renderscript.Target_api) if targetApi == "" && ctx.useSdk() { - switch ctx.sdkVersion() { - case "current", "system_current", "test_current": - // Nothing - default: - targetApi = android.GetNumericSdkVersion(ctx.sdkVersion()) + targetApiLevel := android.ApiLevelOrPanic(ctx, ctx.sdkVersion()) + if targetApiLevel.IsCurrent() || targetApiLevel.IsPreview() { + // If the target level is current or preview, leave the 'target-api' unset. + // This signals to llvm-rs-cc that the development API should be used. + } else { + targetApi = targetApiLevel.String() } } diff --git a/cc/sanitize.go b/cc/sanitize.go index 62e31d1ca..30bce9bff 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -56,10 +56,6 @@ var ( // higher number of "optimized out" stack variables. // b/112437883. "-instcombine-lower-dbg-declare=0", - // TODO(b/159343917): HWASan and GlobalISel don't play nicely, and - // GlobalISel is the default at -O0 on aarch64. - "--aarch64-enable-global-isel-at-O=-1", - "-fast-isel=false", "-hwasan-use-after-scope=1", "-dom-tree-reachability-max-bbs-to-explore=128", } @@ -91,6 +87,8 @@ var ( hostOnlySanitizeFlags = []string{"-fno-sanitize-recover=all"} deviceOnlySanitizeFlags = []string{"-fsanitize-trap=all", "-ftrap-function=abort"} + + noSanitizeLinkRuntimeFlag = "-fno-sanitize-link-runtime" ) type SanitizerType int @@ -411,6 +409,8 @@ func init() { exportedVars.ExportStringListStaticVariable("HostOnlySanitizeFlags", hostOnlySanitizeFlags) exportedVars.ExportStringList("DeviceOnlySanitizeFlags", deviceOnlySanitizeFlags) + exportedVars.ExportStringList("MinimalRuntimeFlags", minimalRuntimeFlags) + // Leave out "-flto" from the slices exported to bazel, as we will use the // dedicated LTO feature for this. For C Flags and Linker Flags, also leave // out the cross DSO flag which will be added separately under the correct conditions. @@ -426,6 +426,8 @@ func init() { exportedVars.ExportString("CfiExportsMapFilename", cfiExportsMapFilename) exportedVars.ExportString("CfiAssemblySupportFlag", cfiAssemblySupportFlag) + exportedVars.ExportString("NoSanitizeLinkRuntimeFlag", noSanitizeLinkRuntimeFlag) + android.RegisterMakeVarsProvider(pctx, cfiMakeVarsProvider) android.RegisterMakeVarsProvider(pctx, hwasanMakeVarsProvider) } @@ -646,10 +648,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. @@ -931,7 +929,7 @@ func (s *sanitize) flags(ctx ModuleContext, flags Flags) Flags { // Bionic and musl sanitizer runtimes have already been added as dependencies so that // the right variant of the runtime will be used (with the "-android" or "-musl" // suffixes), so don't let clang the runtime library. - flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-sanitize-link-runtime") + flags.Local.LdFlags = append(flags.Local.LdFlags, noSanitizeLinkRuntimeFlag) } else { // Host sanitizers only link symbols in the final executable, so // there will always be undefined symbols in intermediate libraries. 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..0be230151 100644 --- a/cc/test.go +++ b/cc/test.go @@ -267,7 +267,7 @@ func (test *testDecorator) gtest() bool { return BoolDefault(test.LinkerProperties.Gtest, true) } -func (test *testDecorator) isolated(ctx BaseModuleContext) bool { +func (test *testDecorator) isolated(ctx android.EarlyModuleContext) bool { return BoolDefault(test.LinkerProperties.Isolated, false) } @@ -641,14 +641,27 @@ type ccTestBazelHandler struct { var _ BazelHandler = (*ccTestBazelHandler)(nil) +// The top level target named $label is a test_suite target, +// not the internal cc_test executable target. +// +// This is to ensure `b test //$label` runs the test_suite target directly, +// which depends on tradefed_test targets, instead of the internal cc_test +// target, which doesn't have tradefed integrations. +// +// However, for cquery, we want the internal cc_test executable target, which +// has the suffix "__tf_internal". +func mixedBuildsTestLabel(label string) string { + return label + "__tf_internal" +} + func (handler *ccTestBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) { bazelCtx := ctx.Config().BazelContext - bazelCtx.QueueBazelRequest(label, cquery.GetCcUnstrippedInfo, android.GetConfigKey(ctx)) + bazelCtx.QueueBazelRequest(mixedBuildsTestLabel(label), cquery.GetCcUnstrippedInfo, android.GetConfigKey(ctx)) } func (handler *ccTestBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) { bazelCtx := ctx.Config().BazelContext - info, err := bazelCtx.GetCcUnstrippedInfo(label, android.GetConfigKey(ctx)) + info, err := bazelCtx.GetCcUnstrippedInfo(mixedBuildsTestLabel(label), android.GetConfigKey(ctx)) if err != nil { ctx.ModuleErrorf(err.Error()) return @@ -669,8 +682,7 @@ func (handler *ccTestBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleC type testBinaryAttributes struct { binaryAttributes - Gtest bool - Isolated bool + Gtest *bool tidyAttributes tradefed.TestConfigAttributes @@ -708,13 +720,15 @@ func testBinaryBp2build(ctx android.TopDownMutatorContext, m *Module) { m.convertTidyAttributes(ctx, &testBinaryAttrs.tidyAttributes) - for _, propIntf := range m.GetProperties() { - if testLinkerProps, ok := propIntf.(*TestLinkerProperties); ok { - testBinaryAttrs.Gtest = proptools.BoolDefault(testLinkerProps.Gtest, true) - testBinaryAttrs.Isolated = proptools.BoolDefault(testLinkerProps.Isolated, true) - break - } - } + testBinary := m.linker.(*testBinary) + gtest := testBinary.gtest() + gtestIsolated := testBinary.isolated(ctx) + // Use the underling bool pointer for Gtest in attrs + // This ensures that if this property is not set in Android.bp file, it will not be set in BUILD file either + // cc_test macro will default gtest to True + testBinaryAttrs.Gtest = testBinary.LinkerProperties.Gtest + + addImplicitGtestDeps(ctx, &testBinaryAttrs, gtest, gtestIsolated) for _, testProps := range m.GetProperties() { if p, ok := testProps.(*TestBinaryProperties); ok { @@ -727,7 +741,7 @@ func testBinaryBp2build(ctx android.TopDownMutatorContext, m *Module) { p.Auto_gen_config, p.Test_options.Test_suite_tag, p.Test_config_template, - getTradefedConfigOptions(ctx, p, testBinaryAttrs.Isolated), + getTradefedConfigOptions(ctx, p, gtestIsolated), &testInstallBase, ) testBinaryAttrs.TestConfigAttributes = testConfigAttributes @@ -747,3 +761,28 @@ func testBinaryBp2build(ctx android.TopDownMutatorContext, m *Module) { }, &testBinaryAttrs) } + +// cc_test that builds using gtest needs some additional deps +// addImplicitGtestDeps makes these deps explicit in the generated BUILD files +func addImplicitGtestDeps(ctx android.BazelConversionPathContext, attrs *testBinaryAttributes, gtest, gtestIsolated bool) { + addDepsAndDedupe := func(lla *bazel.LabelListAttribute, modules []string) { + moduleLabels := android.BazelLabelForModuleDeps(ctx, modules) + lla.Value.Append(moduleLabels) + // Dedupe + lla.Value = bazel.FirstUniqueBazelLabelList(lla.Value) + } + // this must be kept in sync with Soong's implementation in: + // https://cs.android.com/android/_/android/platform/build/soong/+/460fb2d6d546b5ab493a7e5479998c4933a80f73:cc/test.go;l=300-313;drc=ec7314336a2b35ea30ce5438b83949c28e3ac429;bpv=1;bpt=0 + if gtest { + // TODO - b/244433197: Handle canUseSdk + if gtestIsolated { + addDepsAndDedupe(&attrs.Deps, []string{"libgtest_isolated_main"}) + addDepsAndDedupe(&attrs.Dynamic_deps, []string{"liblog"}) + } else { + addDepsAndDedupe(&attrs.Deps, []string{ + "libgtest_main", + "libgtest", + }) + } + } +} diff --git a/cc/testing.go b/cc/testing.go index d346739bd..d1632aaa6 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -423,11 +423,6 @@ func commonDefaultModules() string { export_include_dirs: ["ndk_libc++_shared"], } - ndk_prebuilt_static_stl { - name: "ndk_libandroid_support", - export_include_dirs: ["ndk_libandroid_support"], - } - cc_library_static { name: "libgoogle-benchmark", sdk_version: "current", @@ -573,16 +568,15 @@ var PrepareForTestWithCcDefaultModules = android.GroupFixturePreparers( // Additional files needed in tests that disallow non-existent source. android.MockFS{ - "defaults/cc/common/libc.map.txt": nil, - "defaults/cc/common/libdl.map.txt": nil, - "defaults/cc/common/libm.map.txt": nil, - "defaults/cc/common/ndk_libandroid_support": nil, - "defaults/cc/common/ndk_libc++_shared": nil, - "defaults/cc/common/crtbegin_so.c": nil, - "defaults/cc/common/crtbegin.c": nil, - "defaults/cc/common/crtend_so.c": nil, - "defaults/cc/common/crtend.c": nil, - "defaults/cc/common/crtbrand.c": nil, + "defaults/cc/common/libc.map.txt": nil, + "defaults/cc/common/libdl.map.txt": nil, + "defaults/cc/common/libm.map.txt": nil, + "defaults/cc/common/ndk_libc++_shared": nil, + "defaults/cc/common/crtbegin_so.c": nil, + "defaults/cc/common/crtbegin.c": nil, + "defaults/cc/common/crtend_so.c": nil, + "defaults/cc/common/crtend.c": nil, + "defaults/cc/common/crtbrand.c": nil, "defaults/cc/common/libclang_rt.ubsan_minimal.android_arm64.a": nil, "defaults/cc/common/libclang_rt.ubsan_minimal.android_arm.a": nil, diff --git a/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/cc/vndk.go b/cc/vndk.go index 7a2286eb1..95a5a4f47 100644 --- a/cc/vndk.go +++ b/cc/vndk.go @@ -39,25 +39,34 @@ const ( vndkUsingCoreVariantLibrariesTxt = "vndkcorevariant.libraries.txt" ) -func VndkLibrariesTxtModules(vndkVersion string) []string { +func VndkLibrariesTxtModules(vndkVersion string, ctx android.BaseModuleContext) []string { if vndkVersion == "current" { - return []string{ - llndkLibrariesTxt, + result := []string{ vndkCoreLibrariesTxt, vndkSpLibrariesTxt, vndkPrivateLibrariesTxt, vndkProductLibrariesTxt, } + + // TODO(b/290159430) This part will not be required once deprecation of VNDK + // is handled with 'ro.vndk.version' property + if !ctx.Config().IsVndkDeprecated() { + result = append(result, llndkLibrariesTxt) + } + + return result } // Snapshot vndks have their own *.libraries.VER.txt files. // Note that snapshots don't have "vndkcorevariant.libraries.VER.txt" - return []string{ - insertVndkVersion(llndkLibrariesTxt, vndkVersion), + result := []string{ insertVndkVersion(vndkCoreLibrariesTxt, vndkVersion), insertVndkVersion(vndkSpLibrariesTxt, vndkVersion), insertVndkVersion(vndkPrivateLibrariesTxt, vndkVersion), insertVndkVersion(vndkProductLibrariesTxt, vndkVersion), + insertVndkVersion(llndkLibrariesTxt, vndkVersion), } + + return result } type VndkProperties struct { @@ -519,11 +528,15 @@ func insertVndkVersion(filename string, vndkVersion string) string { } func (txt *vndkLibrariesTxt) GenerateAndroidBuildActions(ctx android.ModuleContext) { - var filename string - if BoolDefault(txt.properties.Insert_vndk_version, true) { + filename := txt.Name() + + shouldInsertVndkVersion := BoolDefault(txt.properties.Insert_vndk_version, true) + // llndk.libraries.txt file installed in the system image should not contain version info. + if ctx.Config().IsVndkDeprecated() && txt.Name() == llndkLibrariesTxt { + shouldInsertVndkVersion = false + } + if shouldInsertVndkVersion { filename = insertVndkVersion(txt.Name(), ctx.DeviceConfig().PlatformVndkVersion()) - } else { - filename = txt.Name() } txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath 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..20e366e8a 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -121,6 +121,10 @@ func runMixedModeBuild(ctx *android.Context, extraNinjaDeps []string) string { defer ctx.EventHandler.End("mixed_build") bazelHook := func() error { + err := ctx.Config().BazelContext.QueueBazelSandwichCqueryRequests(ctx.Config()) + if err != nil { + return err + } return ctx.Config().BazelContext.InvokeBazel(ctx.Config(), ctx) } ctx.SetBeforePrepareBuildActionsHook(bazelHook) @@ -225,7 +229,7 @@ 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 +240,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 @@ -807,9 +814,7 @@ func runBp2Build(ctx *android.Context, extraNinjaDeps []string, metricsDir strin // Run the code-generation phase to convert BazelTargetModules to BUILD files // and print conversion codegenMetrics to the user. codegenContext := bp2build.NewCodegenContext(ctx.Config(), ctx, bp2build.Bp2Build, topDir) - ctx.EventHandler.Do("codegen", func() { - codegenMetrics = bp2build.Codegen(codegenContext) - }) + codegenMetrics = bp2build.Codegen(codegenContext) ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...) diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go index 67cb6cfc8..5c2316a31 100644 --- a/cmd/soong_build/queryview.go +++ b/cmd/soong_build/queryview.go @@ -15,7 +15,6 @@ package main import ( - "android/soong/starlark_import" "io/fs" "io/ioutil" "os" @@ -23,6 +22,7 @@ import ( "android/soong/android" "android/soong/bp2build" + "android/soong/starlark_import" ) // A helper function to generate a Read-only Bazel workspace in outDir @@ -35,8 +35,7 @@ func createBazelWorkspace(ctx *bp2build.CodegenContext, outDir string, generateF panic(err) } - filesToWrite := bp2build.CreateBazelFiles(ctx.Config(), ruleShims, res.BuildDirToTargets(), - ctx.Mode()) + filesToWrite := bp2build.CreateBazelFiles(ruleShims, res.BuildDirToTargets(), ctx.Mode()) bazelRcFiles, err2 := CopyBazelRcFiles() if err2 != nil { return err2 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 c767685bc..afa52cc7b 100644 --- a/genrule/allowlists.go +++ b/genrule/allowlists.go @@ -56,7 +56,6 @@ var ( "RSTest-rscript", "BluetoothGeneratedDumpsysBinarySchema_bfbs", "TracingVMProtoStub_h", - "FrontendStub_h", "VehicleServerProtoStub_cc", "AudioFocusControlProtoStub_cc", "AudioFocusControlProtoStub_h", @@ -98,9 +97,6 @@ var ( "BlueberryFacadeGeneratedStub_cc", "BlueberryFacadeGeneratedStub_h", "BluetoothGeneratedDumpsysDataSchema_h", - "FrontendStub_cc", - "OpenwrtControlServerProto_cc", - "OpenwrtControlServerProto_h", "c2hal_test_genc++", "c2hal_test_genc++_headers", "hidl2aidl_test_gen_aidl", @@ -117,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..aa4295d64 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 { @@ -860,7 +869,7 @@ type bazelGensrcsAttributes struct { Srcs bazel.LabelListAttribute Output_extension *string Tools bazel.LabelListAttribute - Cmd string + Cmd bazel.StringAttribute Data bazel.LabelListAttribute } @@ -908,7 +917,7 @@ type bazelGenruleAttributes struct { Srcs bazel.LabelListAttribute Outs []string Tools bazel.LabelListAttribute - Cmd string + Cmd bazel.StringAttribute } // ConvertWithBp2build converts a Soong module -> Bazel target. @@ -958,14 +967,13 @@ func (m *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { } } - // Replace in and out variables with $< and $@ - var cmd string - if m.properties.Cmd != nil { + replaceVariables := func(cmd string) string { + // Replace in and out variables with $< and $@ if ctx.ModuleType() == "gensrcs" { - cmd = strings.ReplaceAll(*m.properties.Cmd, "$(in)", "$(SRC)") + cmd = strings.ReplaceAll(cmd, "$(in)", "$(SRC)") cmd = strings.ReplaceAll(cmd, "$(out)", "$(OUT)") } else { - cmd = strings.Replace(*m.properties.Cmd, "$(in)", "$(SRCS)", -1) + cmd = strings.Replace(cmd, "$(in)", "$(SRCS)", -1) cmd = strings.Replace(cmd, "$(out)", "$(OUTS)", -1) } cmd = strings.Replace(cmd, "$(genDir)", "$(RULEDIR)", -1) @@ -981,10 +989,26 @@ func (m *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { cmd = strings.Replace(cmd, bpLoc, bazelLoc, -1) cmd = strings.Replace(cmd, bpLocs, bazelLocs, -1) } + return cmd + } + + var cmdProp bazel.StringAttribute + cmdProp.SetValue(replaceVariables(proptools.String(m.properties.Cmd))) + allProductVariableProps := android.ProductVariableProperties(ctx, m) + if productVariableProps, ok := allProductVariableProps["Cmd"]; ok { + for productVariable, value := range productVariableProps { + var cmd string + if strValue, ok := value.(*string); ok && strValue != nil { + cmd = *strValue + } + cmd = replaceVariables(cmd) + cmdProp.SetSelectValue(productVariable.ConfigurationAxis(), productVariable.SelectKey(), &cmd) + } } tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m) + bazelName := m.Name() if ctx.ModuleType() == "gensrcs" { props := bazel.BazelTargetModuleProperties{ Rule_class: "gensrcs", @@ -993,7 +1017,7 @@ func (m *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { attrs := &bazelGensrcsAttributes{ Srcs: srcs, Output_extension: outputExtension, - Cmd: cmd, + Cmd: cmdProp, Tools: tools, Data: data, } @@ -1002,17 +1026,7 @@ func (m *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { Tags: tags, }, attrs) } else { - // The Out prop is not in an immediately accessible field - // in the Module struct, so use GetProperties and cast it - // to the known struct prop. - var outs []string - for _, propIntf := range m.GetProperties() { - if props, ok := propIntf.(*genRuleProperties); ok { - outs = props.Out - break - } - } - bazelName := m.Name() + outs := m.RawOutputFiles(ctx) for _, out := range outs { if out == bazelName { // This is a workaround to circumvent a Bazel warning where a genrule's @@ -1026,7 +1040,7 @@ func (m *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { attrs := &bazelGenruleAttributes{ Srcs: srcs, Outs: outs, - Cmd: cmd, + Cmd: cmdProp, Tools: tools, } props := bazel.BazelTargetModuleProperties{ @@ -1037,6 +1051,72 @@ func (m *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { Tags: tags, }, attrs) } + + if m.needsCcLibraryHeadersBp2build() { + includeDirs := make([]string, len(m.properties.Export_include_dirs)*2) + for i, dir := range m.properties.Export_include_dirs { + includeDirs[i*2] = dir + includeDirs[i*2+1] = filepath.Clean(filepath.Join(ctx.ModuleDir(), dir)) + } + attrs := &ccHeaderLibraryAttrs{ + Hdrs: []string{":" + bazelName}, + Export_includes: includeDirs, + } + props := bazel.BazelTargetModuleProperties{ + Rule_class: "cc_library_headers", + Bzl_load_location: "//build/bazel/rules/cc:cc_library_headers.bzl", + } + ctx.CreateBazelTargetModule(props, android.CommonAttributes{ + Name: m.Name() + genruleHeaderLibrarySuffix, + Tags: tags, + }, attrs) + } +} + +const genruleHeaderLibrarySuffix = "__header_library" + +func (m *Module) needsCcLibraryHeadersBp2build() bool { + return len(m.properties.Export_include_dirs) > 0 +} + +// GenruleCcHeaderMapper is a bazel.LabelMapper function to map genrules to a cc_library_headers +// target when they export multiple include directories. +func GenruleCcHeaderLabelMapper(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) { + mod, exists := ctx.ModuleFromName(label.OriginalModuleName) + if !exists { + return label.Label, false + } + if m, ok := mod.(*Module); ok { + if m.needsCcLibraryHeadersBp2build() { + return label.Label + genruleHeaderLibrarySuffix, true + } + } + return label.Label, false +} + +type ccHeaderLibraryAttrs struct { + Hdrs []string + + Export_includes []string +} + +// RawOutputFfiles returns the raw outputs specified in Android.bp +// This does not contain the fully resolved path relative to the top of the tree +func (g *Module) RawOutputFiles(ctx android.BazelConversionContext) []string { + if ctx.Config().BuildMode != android.Bp2build { + ctx.ModuleErrorf("RawOutputFiles is only supported in bp2build mode") + } + // The Out prop is not in an immediately accessible field + // in the Module struct, so use GetProperties and cast it + // to the known struct prop. + var outs []string + for _, propIntf := range g.GetProperties() { + if props, ok := propIntf.(*genRuleProperties); ok { + outs = props.Out + break + } + } + return outs } var Bool = proptools.Bool @@ -1090,6 +1170,7 @@ func getSandboxingAllowlistSets(ctx android.PathContext) *sandboxingAllowlistSet } }).(*sandboxingAllowlistSets) } + func getSandboxedRuleBuilder(ctx android.ModuleContext, r *android.RuleBuilder) *android.RuleBuilder { if !ctx.DeviceConfig().GenruleSandboxing() { return r.SandboxTools() diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go index 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/aapt2.go b/java/aapt2.go index 7845a0b23..3bb70b53f 100644 --- a/java/aapt2.go +++ b/java/aapt2.go @@ -146,20 +146,25 @@ func aapt2CompileZip(ctx android.ModuleContext, flata android.WritablePath, zip var aapt2LinkRule = pctx.AndroidStaticRule("aapt2Link", blueprint.RuleParams{ - Command: `rm -rf $genDir && ` + - `${config.Aapt2Cmd} link -o $out $flags --java $genDir --proguard $proguardOptions ` + - `--output-text-symbols ${rTxt} $inFlags && ` + - `${config.SoongZipCmd} -write_if_changed -jar -o $genJar -C $genDir -D $genDir &&` + - `${config.ExtractJarPackagesCmd} -i $genJar -o $extraPackages --prefix '--extra-packages '`, + Command: `$preamble` + + `${config.Aapt2Cmd} link -o $out $flags --proguard $proguardOptions ` + + `--output-text-symbols ${rTxt} $inFlags` + + `$postamble`, CommandDeps: []string{ "${config.Aapt2Cmd}", "${config.SoongZipCmd}", - "${config.ExtractJarPackagesCmd}", }, Restat: true, }, - "flags", "inFlags", "proguardOptions", "genDir", "genJar", "rTxt", "extraPackages") + "flags", "inFlags", "proguardOptions", "rTxt", "extraPackages", "preamble", "postamble") + +var aapt2ExtractExtraPackagesRule = pctx.AndroidStaticRule("aapt2ExtractExtraPackages", + blueprint.RuleParams{ + Command: `${config.ExtractJarPackagesCmd} -i $in -o $out --prefix '--extra-packages '`, + CommandDeps: []string{"${config.ExtractJarPackagesCmd}"}, + Restat: true, + }) var fileListToFileRule = pctx.AndroidStaticRule("fileListToFile", blueprint.RuleParams{ @@ -175,12 +180,10 @@ var mergeAssetsRule = pctx.AndroidStaticRule("mergeAssets", }) func aapt2Link(ctx android.ModuleContext, - packageRes, genJar, proguardOptions, rTxt, extraPackages android.WritablePath, + packageRes, genJar, proguardOptions, rTxt android.WritablePath, flags []string, deps android.Paths, compiledRes, compiledOverlay, assetPackages android.Paths, splitPackages android.WritablePaths) { - genDir := android.PathForModuleGen(ctx, "aapt2", "R") - var inFlags []string if len(compiledRes) > 0 { @@ -217,7 +220,7 @@ func aapt2Link(ctx android.ModuleContext, } // Set auxiliary outputs as implicit outputs to establish correct dependency chains. - implicitOutputs := append(splitPackages, proguardOptions, genJar, rTxt, extraPackages) + implicitOutputs := append(splitPackages, proguardOptions, rTxt) linkOutput := packageRes // AAPT2 ignores assets in overlays. Merge them after linking. @@ -232,25 +235,49 @@ func aapt2Link(ctx android.ModuleContext, }) } + // Note the absence of splitPackages. The caller is supposed to compose and provide --split flag + // values via the flags parameter when it wants to split outputs. + // TODO(b/174509108): Perhaps we can process it in this func while keeping the code reasonably + // tidy. + args := map[string]string{ + "flags": strings.Join(flags, " "), + "inFlags": strings.Join(inFlags, " "), + "proguardOptions": proguardOptions.String(), + "rTxt": rTxt.String(), + } + + if genJar != nil { + // Generating java source files from aapt2 was requested, use aapt2LinkAndGenRule and pass it + // genJar and genDir args. + genDir := android.PathForModuleGen(ctx, "aapt2", "R") + ctx.Variable(pctx, "aapt2GenDir", genDir.String()) + ctx.Variable(pctx, "aapt2GenJar", genJar.String()) + implicitOutputs = append(implicitOutputs, genJar) + args["preamble"] = `rm -rf $aapt2GenDir && ` + args["postamble"] = `&& ${config.SoongZipCmd} -write_if_changed -jar -o $aapt2GenJar -C $aapt2GenDir -D $aapt2GenDir && ` + + `rm -rf $aapt2GenDir` + args["flags"] += " --java $aapt2GenDir" + } + ctx.Build(pctx, android.BuildParams{ Rule: aapt2LinkRule, Description: "aapt2 link", Implicits: deps, Output: linkOutput, ImplicitOutputs: implicitOutputs, - // Note the absence of splitPackages. The caller is supposed to compose and provide --split flag - // values via the flags parameter when it wants to split outputs. - // TODO(b/174509108): Perhaps we can process it in this func while keeping the code reasonably - // tidy. - Args: map[string]string{ - "flags": strings.Join(flags, " "), - "inFlags": strings.Join(inFlags, " "), - "proguardOptions": proguardOptions.String(), - "genDir": genDir.String(), - "genJar": genJar.String(), - "rTxt": rTxt.String(), - "extraPackages": extraPackages.String(), - }, + Args: args, + }) +} + +// aapt2ExtractExtraPackages takes a srcjar generated by aapt2 or a classes jar generated by ResourceProcessorBusyBox +// and converts it to a text file containing a list of --extra_package arguments for passing to Make modules so they +// correctly generate R.java entries for packages provided by transitive dependencies. +func aapt2ExtractExtraPackages(ctx android.ModuleContext, out android.WritablePath, in android.Path) { + ctx.Build(pctx, android.BuildParams{ + Rule: aapt2ExtractExtraPackagesRule, + Description: "aapt2 extract extra packages", + Input: in, + Output: out, }) } diff --git a/java/aar.go b/java/aar.go index 29e86e678..308a48cac 100644 --- a/java/aar.go +++ b/java/aar.go @@ -23,6 +23,7 @@ import ( "android/soong/android" "android/soong/bazel" "android/soong/dexpreopt" + "android/soong/ui/metrics/bp2build_metrics_proto" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -31,10 +32,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 +89,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 +152,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 +192,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 +306,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 +329,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,21 +355,34 @@ 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") proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options") 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 srcJar android.WritablePath 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,22 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon }) } - aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt, extraPackages, - linkFlags, linkDeps, compiledRes, compiledOverlay, assetPackages, splitPackages) + if !a.useResourceProcessorBusyBox() { + // the subdir "android" is required to be filtered by package names + srcJar = android.PathForModuleGen(ctx, "android", "R.srcjar") + } + // 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, + 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 +485,145 @@ 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) + aapt2ExtractExtraPackages(ctx, extraPackages, rJar) + transitiveRJars = append(transitiveRJars, rJar) + a.rJar = rJar + } else { + aapt2ExtractExtraPackages(ctx, extraPackages, srcJar) + } + 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 +636,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 +662,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 +691,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 +702,6 @@ type AndroidLibrary struct { androidLibraryProperties androidLibraryProperties aarFile android.WritablePath - - exportedStaticPackages android.Paths } var _ android.OutputFileProducer = (*AndroidLibrary)(nil) @@ -532,10 +716,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 +734,15 @@ 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) + if a.useResourceProcessorBusyBox() { + ctx.CheckbuildFile(a.aapt.rJar) + } else { + ctx.CheckbuildFile(a.aapt.aaptSrcJar) + } // apps manifests are handled by aapt, don't let Module see them a.properties.Manifest = nil @@ -568,7 +754,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 +780,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 +871,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 +939,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) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] { + return a.resourcesNodesDepSet } -func (a *AARImport) ExportedStaticPackages() android.Paths { - return a.exportedStaticPackages +func (a *AARImport) RRODirsDepSet() *android.DepSet[rroDir] { + return android.NewDepSet[rroDir](android.TOPOLOGICAL, nil, nil) } -func (a *AARImport) ExportedManifests() android.Paths { - return android.Paths{a.manifest} -} - -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 +1048,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(), @@ -874,49 +1071,73 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { aapt2CompileZip(ctx, flata, a.aarPath, "res", compileFlags) a.exportPackage = android.PathForModuleOut(ctx, "package-res.apk") - // 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, nil, proguardOptionsFile, a.rTxt, 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) + + aapt2ExtractExtraPackages(ctx, a.extraAaptPackagesFile, a.rJar) + + 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 +1146,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) { @@ -1007,6 +1229,8 @@ func AARImportFactory() android.Module { type bazelAapt struct { Manifest bazel.Label Resource_files bazel.LabelListAttribute + Assets_dir bazel.StringAttribute + Assets bazel.LabelListAttribute } type bazelAndroidLibrary struct { @@ -1021,7 +1245,7 @@ type bazelAndroidLibraryImport struct { Sdk_version bazel.StringAttribute } -func (a *aapt) convertAaptAttrsWithBp2Build(ctx android.TopDownMutatorContext) *bazelAapt { +func (a *aapt) convertAaptAttrsWithBp2Build(ctx android.TopDownMutatorContext) (*bazelAapt, bool) { manifest := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") resourceFiles := bazel.LabelList{ @@ -1031,10 +1255,30 @@ func (a *aapt) convertAaptAttrsWithBp2Build(ctx android.TopDownMutatorContext) * files := android.RootToModuleRelativePaths(ctx, androidResourceGlob(ctx, dir)) resourceFiles.Includes = append(resourceFiles.Includes, files...) } + + assetsDir := bazel.StringAttribute{} + var assets bazel.LabelList + for i, dir := range android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets") { + if i > 0 { + ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "multiple asset_dirs") + return &bazelAapt{}, false + } + // Assets_dirs are relative to the module dir when specified, but if the default in used in + // PathsWithOptionalDefaultForModuleSrc, then dir is relative to the top. + assetsRelDir, error := filepath.Rel(ctx.ModuleDir(), dir.Rel()) + if error != nil { + assetsRelDir = dir.Rel() + } + assetsDir.Value = proptools.StringPtr(assetsRelDir) + assets = bazel.MakeLabelList(android.RootToModuleRelativePaths(ctx, androidResourceGlob(ctx, dir))) + + } return &bazelAapt{ android.BazelLabelForModuleSrcSingle(ctx, manifest), bazel.MakeLabelListAttribute(resourceFiles), - } + assetsDir, + bazel.MakeLabelListAttribute(assets), + }, true } func (a *AARImport) ConvertWithBp2build(ctx android.TopDownMutatorContext) { @@ -1091,7 +1335,11 @@ func AndroidLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperti } func (a *AndroidLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) { - commonAttrs, bp2buildInfo := a.convertLibraryAttrsBp2Build(ctx) + commonAttrs, bp2buildInfo, supported := a.convertLibraryAttrsBp2Build(ctx) + if !supported { + return + } + depLabels := bp2buildInfo.DepLabels deps := depLabels.Deps @@ -1103,6 +1351,10 @@ func (a *AndroidLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) name := a.Name() props := AndroidLibraryBazelTargetModuleProperties() + aaptAttrs, supported := a.convertAaptAttrsWithBp2Build(ctx) + if !supported { + return + } ctx.CreateBazelTargetModule( props, android.CommonAttributes{Name: name}, @@ -1112,7 +1364,7 @@ func (a *AndroidLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) Deps: deps, Exports: depLabels.StaticDeps, }, - a.convertAaptAttrsWithBp2Build(ctx), + aaptAttrs, }, ) 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..1d1ea97f9 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 @@ -997,7 +1022,13 @@ func (a *AndroidApp) OutputFiles(tag string) (android.Paths, error) { case ".aapt.proguardOptionsFile": return []android.Path{a.proguardOptionsFile}, nil case ".aapt.srcjar": - return []android.Path{a.aaptSrcJar}, nil + if a.aaptSrcJar != nil { + return []android.Path{a.aaptSrcJar}, nil + } + case ".aapt.jar": + if a.rJar != nil { + return []android.Path{a.rJar}, nil + } case ".export-package.apk": return []android.Path{a.exportPackage}, nil } @@ -1571,7 +1602,9 @@ func androidAppCertificateBp2Build(ctx android.TopDownMutatorContext, module *An } type manifestValueAttribute struct { - MinSdkVersion *string + MinSdkVersion *string + MaxSdkVersion *string + TargetSdkVersion *string } type bazelAndroidAppAttributes struct { @@ -1586,14 +1619,19 @@ type bazelAndroidAppAttributes struct { // ConvertWithBp2build is used to convert android_app to Bazel. func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) { - commonAttrs, bp2BuildInfo := a.convertLibraryAttrsBp2Build(ctx) + commonAttrs, bp2BuildInfo, supported := a.convertLibraryAttrsBp2Build(ctx) + if !supported { + return + } depLabels := bp2BuildInfo.DepLabels deps := depLabels.Deps deps.Append(depLabels.StaticDeps) - aapt := a.convertAaptAttrsWithBp2Build(ctx) - + aapt, supported := a.convertAaptAttrsWithBp2Build(ctx) + if !supported { + return + } certificate, certificateName := android.BazelStringOrLabelFromProp(ctx, a.overridableAppProperties.Certificate) manifestValues := &manifestValueAttribute{} @@ -1601,12 +1639,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_builder.go b/java/app_builder.go index d20a6bfe4..d397ff7f5 100644 --- a/java/app_builder.go +++ b/java/app_builder.go @@ -225,8 +225,6 @@ func BuildBundleModule(ctx android.ModuleContext, outputFile android.WritablePat }) } -const jniJarOutputPathString = "jniJarOutput.zip" - func TransformJniLibsToJar( ctx android.ModuleContext, outputFile android.WritablePath, @@ -258,7 +256,10 @@ func TransformJniLibsToJar( rule = zipRE args["implicits"] = strings.Join(deps.Strings(), ",") } - jniJarPath := android.PathForModuleOut(ctx, jniJarOutputPathString) + var jniJarPath android.WritablePath = android.PathForModuleOut(ctx, "jniJarOutput.zip") + if len(prebuiltJniPackages) == 0 { + jniJarPath = outputFile + } ctx.Build(pctx, android.BuildParams{ Rule: rule, Description: "zip jni libs", @@ -266,12 +267,26 @@ func TransformJniLibsToJar( Implicits: deps, Args: args, }) - ctx.Build(pctx, android.BuildParams{ - Rule: mergeAssetsRule, - Description: "merge prebuilt JNI packages", - Inputs: append(prebuiltJniPackages, jniJarPath), - Output: outputFile, - }) + if len(prebuiltJniPackages) > 0 { + var mergeJniJarPath android.WritablePath = android.PathForModuleOut(ctx, "mergeJniJarOutput.zip") + if !uncompressJNI { + mergeJniJarPath = outputFile + } + ctx.Build(pctx, android.BuildParams{ + Rule: mergeAssetsRule, + Description: "merge prebuilt JNI packages", + Inputs: append(prebuiltJniPackages, jniJarPath), + Output: mergeJniJarPath, + }) + + if uncompressJNI { + ctx.Build(pctx, android.BuildParams{ + Rule: uncompressEmbeddedJniLibsRule, + Input: mergeJniJarPath, + Output: outputFile, + }) + } + } } func (a *AndroidApp) generateJavaUsedByApex(ctx android.ModuleContext) { diff --git a/java/app_import.go b/java/app_import.go index 9c0196039..ad1765e9d 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -17,6 +17,7 @@ package java // This file contains the module implementations for android_app_import and android_test_import. import ( + "fmt" "reflect" "github.com/google/blueprint" @@ -50,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 " + @@ -60,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) { @@ -334,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 @@ -375,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, }) } @@ -410,6 +444,15 @@ func (a *AndroidAppImport) OutputFile() android.Path { return a.outputFile } +func (a *AndroidAppImport) OutputFiles(tag string) (android.Paths, error) { + switch tag { + case "": + return []android.Path{a.outputFile}, nil + default: + return nil, fmt.Errorf("unsupported module reference tag %q", tag) + } +} + func (a *AndroidAppImport) JacocoReportClassesFile() android.Path { return nil } diff --git a/java/app_test.go b/java/app_test.go index 0f98416d2..8474ea7d6 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:" @@ -1232,7 +1742,7 @@ func TestJNIABI(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { app := ctx.ModuleForTests(test.name, "android_common") - jniLibZip := app.Output(jniJarOutputPathString) + jniLibZip := app.Output("jnilibs.zip") var abis []string args := strings.Fields(jniLibZip.Args["jarArgs"]) for i := 0; i < len(args); i++ { @@ -1365,7 +1875,7 @@ func TestJNIPackaging(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { app := ctx.ModuleForTests(test.name, "android_common") - jniLibZip := app.MaybeOutput(jniJarOutputPathString) + jniLibZip := app.MaybeOutput("jnilibs.zip") if g, w := (jniLibZip.Rule != nil), test.packaged; g != w { t.Errorf("expected jni packaged %v, got %v", w, g) } @@ -1456,7 +1966,7 @@ func TestJNISDK(t *testing.T) { t.Run(test.name, func(t *testing.T) { app := ctx.ModuleForTests(test.name, "android_common") - jniLibZip := app.MaybeOutput(jniJarOutputPathString) + jniLibZip := app.MaybeOutput("jnilibs.zip") if len(jniLibZip.Implicits) != 1 { t.Fatalf("expected exactly one jni library, got %q", jniLibZip.Implicits.Strings()) } @@ -2476,7 +2986,7 @@ func TestStl(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { app := ctx.ModuleForTests(test.name, "android_common") - jniLibZip := app.Output(jniJarOutputPathString) + jniLibZip := app.Output("jnilibs.zip") var jnis []string args := strings.Fields(jniLibZip.Args["jarArgs"]) for i := 0; i < len(args); i++ { diff --git a/java/base.go b/java/base.go index 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..debf49a00 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,14 +51,18 @@ 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 && ` + - `rm -rf "$srcJarDir"`, + `$annoSrcJarTemplate${config.SoongZipCmd} -jar -o $annoSrcJar.tmp -C $annoDir -D $annoDir && ` + + `$zipTemplate${config.SoongZipCmd} -jar -o $out.tmp -C $outDir -D $outDir && ` + + `if ! cmp -s "$out.tmp" "$out"; then mv "$out.tmp" "$out"; fi && ` + + `if ! cmp -s "$annoSrcJar.tmp" "$annoSrcJar"; then mv "$annoSrcJar.tmp" "$annoSrcJar"; fi && ` + + `rm -rf "$srcJarDir" "$outDir"`, CommandDeps: []string{ "${config.JavacCmd}", "${config.SoongZipCmd}", "${config.ZipSyncCmd}", }, CommandOrderOnly: []string{"${config.SoongJavacWrapper}"}, + Restat: true, Rspfile: "$out.rsp", RspfileContent: "$in", }, map[string]*remoteexec.REParams{ @@ -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/core-libraries/Android.bp b/java/core-libraries/Android.bp index eadd9c697..4380f4f5c 100644 --- a/java/core-libraries/Android.bp +++ b/java/core-libraries/Android.bp @@ -55,6 +55,19 @@ java_library { ], } +java_api_library { + name: "core.current.stubs.from-text", + api_surface: "core", + api_contributions: [ + "art.module.public.api.stubs.source.api.contribution", + "conscrypt.module.public.api.stubs.source.api.contribution", + "i18n.module.public.api.stubs.source.api.contribution", + ], + libs: [ + "stub-annotations", + ], +} + java_library { name: "core.current.stubs", defaults: [ @@ -146,12 +159,42 @@ java_system_modules { ], } +java_defaults { + name: "core.module_lib.stubs.defaults", + visibility: ["//visibility:private"], + sdk_version: "none", + system_modules: "none", +} + // A stubs target containing the parts of the public SDK & @SystemApi(MODULE_LIBRARIES) API // provided by the core libraries. // // Don't use this directly, use "sdk_version: module_current". java_library { name: "core.module_lib.stubs", + defaults: [ + "core.module_lib.stubs.defaults", + ], + static_libs: [ + "core.module_lib.stubs.from-source", + ], + product_variables: { + build_from_text_stub: { + static_libs: [ + "core.module_lib.stubs.from-text", + ], + exclude_static_libs: [ + "core.module_lib.stubs.from-source", + ], + }, + }, +} + +java_library { + name: "core.module_lib.stubs.from-source", + defaults: [ + "core.module_lib.stubs.defaults", + ], static_libs: [ "art.module.public.api.stubs.module_lib", @@ -161,9 +204,6 @@ java_library { "conscrypt.module.public.api.stubs", "i18n.module.public.api.stubs", ], - sdk_version: "none", - system_modules: "none", - visibility: ["//visibility:private"], } // Produces a dist file that is used by the @@ -237,6 +277,32 @@ java_library { ], } +java_defaults { + name: "android_core_platform_stubs_current_contributions", + api_surface: "core_platform", + api_contributions: [ + "art.module.public.api.stubs.source.api.contribution", + "art.module.public.api.stubs.source.system.api.contribution", + "art.module.public.api.stubs.source.module_lib.api.contribution", + "conscrypt.module.platform.api.stubs.source.api.contribution", + "i18n.module.public.api.stubs.source.api.contribution", + ], +} + +java_api_library { + name: "legacy.core.platform.api.stubs.from-text", + api_surface: "core_platform", + defaults: [ + "android_core_platform_stubs_current_contributions", + ], + api_contributions: [ + "legacy.i18n.module.platform.api.stubs.source.api.contribution", + ], + libs: [ + "stub-annotations", + ], +} + java_library { name: "legacy.core.platform.api.stubs", visibility: core_platform_visibility, @@ -249,10 +315,10 @@ java_library { product_variables: { build_from_text_stub: { static_libs: [ - "stable.core.platform.api.stubs.from-text", + "legacy.core.platform.api.stubs.from-text", ], exclude_static_libs: [ - "stable.core.platform.api.stubs.from-source", + "legacy.core.platform.api.stubs.from-source", ], }, }, @@ -300,6 +366,20 @@ java_library { ], } +java_api_library { + name: "stable.core.platform.api.stubs.from-text", + api_surface: "core_platform", + defaults: [ + "android_core_platform_stubs_current_contributions", + ], + api_contributions: [ + "stable.i18n.module.platform.api.stubs.source.api.contribution", + ], + libs: [ + "stub-annotations", + ], +} + java_library { name: "stable.core.platform.api.stubs", visibility: core_platform_visibility, diff --git a/java/core-libraries/TxtStubLibraries.bp b/java/core-libraries/TxtStubLibraries.bp index 0cf0f360b..c46f8b8ea 100644 --- a/java/core-libraries/TxtStubLibraries.bp +++ b/java/core-libraries/TxtStubLibraries.bp @@ -57,19 +57,23 @@ java_library { ], } -java_library { +java_api_library { name: "core.module_lib.stubs.from-text", - static_libs: [ - "art.module.public.api.stubs.module_lib.from-text", + api_surface: "module-lib", + api_contributions: [ + "art.module.public.api.stubs.source.api.contribution", + "art.module.public.api.stubs.source.system.api.contribution", + "art.module.public.api.stubs.source.module_lib.api.contribution", - // Replace the following with the module-lib correspondence when Conscrypt or i18N module + // Add the module-lib correspondence when Conscrypt or i18N module // provides @SystemApi(MODULE_LIBRARIES). Currently, assume that only ART module provides // @SystemApi(MODULE_LIBRARIES). - "conscrypt.module.public.api.stubs.from-text", - "i18n.module.public.api.stubs.from-text", + "conscrypt.module.public.api.stubs.source.api.contribution", + "i18n.module.public.api.stubs.source.api.contribution", + ], + libs: [ + "stub-annotations", ], - sdk_version: "none", - system_modules: "none", visibility: ["//visibility:private"], } diff --git a/java/device_host_converter.go b/java/device_host_converter.go index 3581040f8..5460dc993 100644 --- a/java/device_host_converter.go +++ b/java/device_host_converter.go @@ -143,6 +143,8 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont ResourceJars: d.resourceJars, SrcJarArgs: d.srcJarArgs, SrcJarDeps: d.srcJarDeps, + // TODO: Not sure if aconfig flags that have been moved between device and host variants + // make sense. }) } diff --git a/java/device_host_converter_test.go b/java/device_host_converter_test.go index 3c9a0f3f1..3413da03d 100644 --- a/java/device_host_converter_test.go +++ b/java/device_host_converter_test.go @@ -135,6 +135,7 @@ func TestHostForDevice(t *testing.T) { hostModule := ctx.ModuleForTests("host_module", config.BuildOSCommonTarget.String()) hostJavac := hostModule.Output("javac/host_module.jar") + hostJavacHeader := hostModule.Output("javac-header/host_module.jar") hostRes := hostModule.Output("res/host_module.jar") hostImportModule := ctx.ModuleForTests("host_import_module", config.BuildOSCommonTarget.String()) @@ -148,7 +149,7 @@ func TestHostForDevice(t *testing.T) { // check classpath of device module with dependency on host_for_device_module expectedClasspath := "-classpath " + strings.Join(android.Paths{ - hostJavac.Output, + hostJavacHeader.Output, hostImportCombined.Output, }.Strings(), ":") diff --git a/java/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/droiddoc.go b/java/droiddoc.go index d4ead12c8..3ba306554 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -699,7 +699,6 @@ func javadocCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs andro cmd := rule.Command(). BuiltTool("soong_javac_wrapper").Tool(config.JavadocCmd(ctx)). Flag(config.JavacVmFlags). - FlagWithArg("-encoding ", "UTF-8"). FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "javadoc.rsp"), srcs). FlagWithInput("@", srcJarList) diff --git a/java/droidstubs.go b/java/droidstubs.go index 151c94a43..f05ef1fdd 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -512,21 +512,19 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")). Flag(config.JavacVmFlags). Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED"). - FlagWithArg("-encoding ", "UTF-8"). - FlagWithArg("-source ", javaVersion.String()). + FlagWithArg("--java-source ", javaVersion.String()). FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs). FlagWithInput("@", srcJarList) - if len(bootclasspath) > 0 { - cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":") + // Metalava does not differentiate between bootclasspath and classpath and has not done so for + // years, so it is unlikely to change any time soon. + combinedPaths := append(([]android.Path)(nil), bootclasspath.Paths()...) + combinedPaths = append(combinedPaths, classpath.Paths()...) + if len(combinedPaths) > 0 { + cmd.FlagWithInputList("--classpath ", combinedPaths, ":") } - if len(classpath) > 0 { - cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":") - } - - cmd.Flag("--no-banner"). - Flag("--color"). + cmd.Flag("--color"). Flag("--quiet"). Flag("--format=v2"). FlagWithArg("--repeat-errors-max ", "10"). @@ -696,6 +694,13 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { cmd.FlagWithArg("--error-message:compatibility:released ", msg) } + if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") { + // Pass the current API file into metalava so it can use it as the basis for determining how to + // generate the output signature files (both api and removed). + currentApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file)) + cmd.FlagWithInput("--use-same-format-as ", currentApiFile) + } + if generateStubs { rule.Command(). BuiltTool("soong_zip"). diff --git a/java/fuzz_test.go b/java/fuzz_test.go index dd1e96b3e..f29c91327 100644 --- a/java/fuzz_test.go +++ b/java/fuzz_test.go @@ -71,8 +71,8 @@ func TestJavaFuzz(t *testing.T) { } baz := result.ModuleForTests("baz", osCommonTarget).Rule("javac").Output.String() - barOut := filepath.Join("out", "soong", ".intermediates", "bar", osCommonTarget, "javac", "bar.jar") - bazOut := filepath.Join("out", "soong", ".intermediates", "baz", osCommonTarget, "javac", "baz.jar") + barOut := filepath.Join("out", "soong", ".intermediates", "bar", osCommonTarget, "javac-header", "bar.jar") + bazOut := filepath.Join("out", "soong", ".intermediates", "baz", osCommonTarget, "javac-header", "baz.jar") android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], barOut) android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], bazOut) diff --git a/java/generated_java_library.go b/java/generated_java_library.go index 1b3de9fe0..f9baa85e4 100644 --- a/java/generated_java_library.go +++ b/java/generated_java_library.go @@ -30,7 +30,7 @@ type GeneratedJavaLibraryCallbacks interface { // Called from inside GenerateAndroidBuildActions. Add the build rules to // make the srcjar, and return the path to it. - GenerateSourceJarBuildActions(ctx android.ModuleContext) android.Path + GenerateSourceJarBuildActions(module *GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path } // GeneratedJavaLibraryModuleFactory provides a utility for modules that are generated @@ -88,7 +88,7 @@ func (module *GeneratedJavaLibraryModule) GenerateAndroidBuildActions(ctx androi checkPropertyEmpty(ctx, module, "plugins", module.Library.properties.Plugins) checkPropertyEmpty(ctx, module, "exported_plugins", module.Library.properties.Exported_plugins) - srcJarPath := module.callbacks.GenerateSourceJarBuildActions(ctx) + srcJarPath := module.callbacks.GenerateSourceJarBuildActions(module, ctx) module.Library.properties.Generated_srcjars = append(module.Library.properties.Generated_srcjars, srcJarPath) module.Library.GenerateAndroidBuildActions(ctx) } diff --git a/java/generated_java_library_test.go b/java/generated_java_library_test.go index 68f1f7edd..7f52fd108 100644 --- a/java/generated_java_library_test.go +++ b/java/generated_java_library_test.go @@ -36,7 +36,8 @@ type JavaGenLibTestCallbacks struct { func (callbacks *JavaGenLibTestCallbacks) DepsMutator(module *GeneratedJavaLibraryModule, ctx android.BottomUpMutatorContext) { } -func (callbacks *JavaGenLibTestCallbacks) GenerateSourceJarBuildActions(ctx android.ModuleContext) android.Path { +func (callbacks *JavaGenLibTestCallbacks) GenerateSourceJarBuildActions(module *GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path { + module.AddAconfigIntermediate(android.PathForOutput(ctx, "aconfig_cache_file")) return android.PathForOutput(ctx, "blah.srcjar") } diff --git a/java/hiddenapi.go b/java/hiddenapi.go index d25096b15..4d08b8307 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -106,7 +106,7 @@ func (h *hiddenAPI) initHiddenAPI(ctx android.ModuleContext, dexJar OptionalDexJ h.uncompressDexState = uncompressedDexState // If hiddenapi processing is disabled treat this as inactive. - if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { + if ctx.Config().DisableHiddenApiChecks() { return } diff --git a/java/hiddenapi_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..8ec17971a 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -121,8 +121,8 @@ type hiddenAPISingleton struct { // hiddenAPI singleton rules func (h *hiddenAPISingleton) GenerateBuildActions(ctx android.SingletonContext) { - // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true - if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { + // Don't run any hiddenapi rules if hiddenapi checks are disabled + if ctx.Config().DisableHiddenApiChecks() { return } @@ -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..70aba8e2c 100644 --- a/java/java.go +++ b/java/java.go @@ -26,6 +26,7 @@ import ( "android/soong/bazel" "android/soong/bazel/cquery" "android/soong/remoteexec" + "android/soong/ui/metrics/bp2build_metrics_proto" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -274,7 +275,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 +684,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 +700,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 +738,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { } }) j.exportedProguardFlagFiles = android.FirstUniquePaths(j.exportedProguardFlagFiles) + } func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) { @@ -1468,6 +1479,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 { @@ -1670,6 +1683,9 @@ type JavaApiLibraryProperties struct { // extracting the compiled class files provided by the // full_api_surface_stub module. Full_api_surface_stub *string + + // Version of previously released API file for compatibility check. + Previous_api *string `android:"path"` } func ApiLibraryFactory() android.Module { @@ -1713,11 +1729,9 @@ func metalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder, cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")). Flag(config.JavacVmFlags). Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED"). - 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"). @@ -1801,6 +1815,28 @@ func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { } } +// API signature file names sorted from +// the narrowest api scope to the widest api scope +var scopeOrderedSourceFileNames = allApiScopes.Strings( + func(s *apiScope) string { return s.apiFilePrefix + "current.txt" }) + +func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFiles android.Paths) android.Paths { + sortedSrcFiles := android.Paths{} + + for _, scopeSourceFileName := range scopeOrderedSourceFileNames { + for _, sourceFileName := range srcFiles { + if sourceFileName.Base() == scopeSourceFileName { + sortedSrcFiles = append(sortedSrcFiles, sourceFileName) + } + } + } + if len(srcFiles) != len(sortedSrcFiles) { + ctx.ModuleErrorf("Unrecognizable source file found within %s", srcFiles) + } + + return sortedSrcFiles +} + func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { rule := android.NewRuleBuilder(pctx, ctx) @@ -1851,10 +1887,18 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.ModuleErrorf("Error: %s has an empty api file.", ctx.ModuleName()) } + srcFiles = al.sortApiFilesByApiScope(ctx, srcFiles) + cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir) al.stubsFlags(ctx, cmd, stubsDir) + migratingNullability := String(al.properties.Previous_api) != "" + if migratingNullability { + previousApi := android.PathForModuleSrc(ctx, String(al.properties.Previous_api)) + cmd.FlagWithInput("--migrate-nullness ", previousApi) + } + al.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar") al.stubsJarWithoutStaticLibs = android.PathForModuleOut(ctx, "metalava", "stubs.jar") al.stubsJar = android.PathForModuleOut(ctx, ctx.ModuleName(), fmt.Sprintf("%s.jar", ctx.ModuleName())) @@ -1878,8 +1922,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 +1957,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 +2279,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 +2700,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 +2814,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 +2852,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 @@ -2816,24 +2861,21 @@ func xsdConfigJavaTarget(ctx android.BazelConversionPathContext, mod blueprint.M // which has other non-attribute information needed for bp2build conversion // that needs different handling depending on the module types, and thus needs // to be returned to the calling function. -func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) (*javaCommonAttributes, *bp2BuildJavaInfo) { +func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) (*javaCommonAttributes, *bp2BuildJavaInfo, bool) { 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) - + if archProps.Jarjar_rules != nil { + ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "jarjar_rules") + return &javaCommonAttributes{}, &bp2BuildJavaInfo{}, false + } } } } @@ -2841,6 +2883,7 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) javaSrcPartition := "java" protoSrcPartition := "proto" + xsdSrcPartition := "xsd" logtagSrcPartition := "logtag" aidlSrcPartition := "aidl" kotlinPartition := "kotlin" @@ -2849,6 +2892,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 +2900,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 +2955,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 +3010,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 +3027,7 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) } } } - depLabels.StaticDeps.Value.Append(staticDeps) + depLabels.StaticDeps.Append(staticDeps) hasKotlin := !kotlinSrcs.IsEmpty() commonAttrs.kotlinAttributes = &kotlinAttributes{ @@ -2986,7 +3043,7 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) hasKotlin: hasKotlin, } - return commonAttrs, bp2BuildInfo + return commonAttrs, bp2BuildInfo, true } type javaLibraryAttributes struct { @@ -3016,7 +3073,10 @@ func javaLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperties } func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) { - commonAttrs, bp2BuildInfo := m.convertLibraryAttrsBp2Build(ctx) + commonAttrs, bp2BuildInfo, supported := m.convertLibraryAttrsBp2Build(ctx) + if !supported { + return + } depLabels := bp2BuildInfo.DepLabels deps := depLabels.Deps @@ -3063,7 +3123,10 @@ type javaBinaryHostAttributes struct { // JavaBinaryHostBp2Build is for java_binary_host bp2build. func javaBinaryHostBp2Build(ctx android.TopDownMutatorContext, m *Binary) { - commonAttrs, bp2BuildInfo := m.convertLibraryAttrsBp2Build(ctx) + commonAttrs, bp2BuildInfo, supported := m.convertLibraryAttrsBp2Build(ctx) + if !supported { + return + } depLabels := bp2BuildInfo.DepLabels deps := depLabels.Deps @@ -3140,13 +3203,17 @@ func javaBinaryHostBp2Build(ctx android.TopDownMutatorContext, m *Binary) { type javaTestHostAttributes struct { *javaCommonAttributes + Srcs bazel.LabelListAttribute Deps bazel.LabelListAttribute Runtime_deps bazel.LabelListAttribute } // javaTestHostBp2Build is for java_test_host bp2build. func javaTestHostBp2Build(ctx android.TopDownMutatorContext, m *TestHost) { - commonAttrs, bp2BuildInfo := m.convertLibraryAttrsBp2Build(ctx) + commonAttrs, bp2BuildInfo, supported := m.convertLibraryAttrsBp2Build(ctx) + if !supported { + return + } depLabels := bp2BuildInfo.DepLabels deps := depLabels.Deps @@ -3176,8 +3243,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 +3359,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..6110e21cb 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -1864,12 +1864,12 @@ func TestJavaApiLibraryAndProviderLink(t *testing.T) { provider_bp_a := ` java_api_contribution { name: "foo1", - api_file: "foo1.txt", + api_file: "current.txt", } ` provider_bp_b := `java_api_contribution { name: "foo2", - api_file: "foo2.txt", + api_file: "current.txt", } ` ctx, _ := testJavaWithFS(t, ` @@ -1897,11 +1897,11 @@ func TestJavaApiLibraryAndProviderLink(t *testing.T) { }{ { moduleName: "bar1", - sourceTextFileDirs: []string{"a/foo1.txt"}, + sourceTextFileDirs: []string{"a/current.txt"}, }, { moduleName: "bar2", - sourceTextFileDirs: []string{"a/foo1.txt", "b/foo2.txt", "api1/current.txt", "api2/current.txt"}, + sourceTextFileDirs: []string{"a/current.txt", "b/current.txt", "api1/current.txt", "api2/current.txt"}, }, } for _, c := range testcases { @@ -1918,25 +1918,25 @@ func TestJavaApiLibraryAndDefaultsLink(t *testing.T) { provider_bp_a := ` java_api_contribution { name: "foo1", - api_file: "foo1.txt", + api_file: "current.txt", } ` provider_bp_b := ` java_api_contribution { name: "foo2", - api_file: "foo2.txt", + api_file: "current.txt", } ` provider_bp_c := ` java_api_contribution { name: "foo3", - api_file: "foo3.txt", + api_file: "current.txt", } ` provider_bp_d := ` java_api_contribution { name: "foo4", - api_file: "foo4.txt", + api_file: "current.txt", } ` ctx, _ := testJavaWithFS(t, ` @@ -1985,15 +1985,15 @@ func TestJavaApiLibraryAndDefaultsLink(t *testing.T) { }{ { moduleName: "bar1", - sourceTextFileDirs: []string{"a/foo1.txt"}, + sourceTextFileDirs: []string{"a/current.txt"}, }, { moduleName: "bar2", - sourceTextFileDirs: []string{"a/foo1.txt", "b/foo2.txt"}, + sourceTextFileDirs: []string{"a/current.txt", "b/current.txt"}, }, { moduleName: "bar3", - sourceTextFileDirs: []string{"c/foo3.txt", "a/foo1.txt", "b/foo2.txt", "d/foo4.txt", "api1/current.txt", "api2/current.txt"}, + sourceTextFileDirs: []string{"c/current.txt", "a/current.txt", "b/current.txt", "d/current.txt", "api1/current.txt", "api2/current.txt"}, }, } for _, c := range testcases { @@ -2010,13 +2010,13 @@ func TestJavaApiLibraryJarGeneration(t *testing.T) { provider_bp_a := ` java_api_contribution { name: "foo1", - api_file: "foo1.txt", + api_file: "current.txt", } ` provider_bp_b := ` java_api_contribution { name: "foo2", - api_file: "foo2.txt", + api_file: "current.txt", } ` ctx, _ := testJavaWithFS(t, ` @@ -2063,13 +2063,13 @@ func TestJavaApiLibraryLibsLink(t *testing.T) { provider_bp_a := ` java_api_contribution { name: "foo1", - api_file: "foo1.txt", + api_file: "current.txt", } ` provider_bp_b := ` java_api_contribution { name: "foo2", - api_file: "foo2.txt", + api_file: "current.txt", } ` lib_bp_a := ` @@ -2138,13 +2138,13 @@ func TestJavaApiLibraryStaticLibsLink(t *testing.T) { provider_bp_a := ` java_api_contribution { name: "foo1", - api_file: "foo1.txt", + api_file: "current.txt", } ` provider_bp_b := ` java_api_contribution { name: "foo2", - api_file: "foo2.txt", + api_file: "current.txt", } ` lib_bp_a := ` @@ -2212,13 +2212,13 @@ func TestJavaApiLibraryFullApiSurfaceStub(t *testing.T) { provider_bp_a := ` java_api_contribution { name: "foo1", - api_file: "foo1.txt", + api_file: "current.txt", } ` provider_bp_b := ` java_api_contribution { name: "foo2", - api_file: "foo2.txt", + api_file: "current.txt", } ` lib_bp_a := ` @@ -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/kotlin.go b/java/kotlin.go index f28d6c737..3637e2e71 100644 --- a/java/kotlin.go +++ b/java/kotlin.go @@ -42,7 +42,7 @@ var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports ` -P plugin:org.jetbrains.kotlin.jvm.abi:outputDir=$headerClassesDir && ` + `${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir -write_if_changed && ` + `${config.SoongZipCmd} -jar -o $headerJar -C $headerClassesDir -D $headerClassesDir -write_if_changed && ` + - `rm -rf "$srcJarDir"`, + `rm -rf "$srcJarDir" "$classesDir" "$headerClassesDir"`, CommandDeps: []string{ "${config.KotlincCmd}", "${config.KotlinCompilerJar}", diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt index 1bb49962c..8494d029e 100644 --- a/java/lint_defaults.txt +++ b/java/lint_defaults.txt @@ -122,3 +122,17 @@ --warning_check RemoteViewLayout --warning_check SupportAnnotationUsage --warning_check UniqueConstants + +# TODO(b/294098365): these checks fail in AOSP, but pass downstream +--warning_check ForegroundServiceType +--warning_check MutableImplicitPendingIntent + +--warning_check ExactAlarm +--warning_check ExpiredTargetSdkVersion +--warning_check ForegroundServicePermission +--warning_check ObsoleteSdkInt +--warning_check ScheduleExactAlarm +--warning_check StartActivityAndCollapseDeprecated +--warning_check UnspecifiedRegisterReceiverFlag +--warning_check WearMaterialTheme +--warning_check WearStandaloneAppFlag diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index 0d4db7ca1..ade739552 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -113,7 +113,7 @@ func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorCon } func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpMutatorContext) { - if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { + if ctx.Config().DisableHiddenApiChecks() { return } @@ -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 @@ -275,10 +275,10 @@ func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android. bootDexJarByModule := extractBootDexJarsFromModules(ctx, modules) - // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true. This is a performance + // Don't run any hiddenapi rules if hidden api checks are disabled. This is a performance // optimization that can be used to reduce the incremental build time but as its name suggests it // can be unsafe to use, e.g. when the changes affect anything that goes on the bootclasspath. - if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { + if ctx.Config().DisableHiddenApiChecks() { paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV} for _, path := range paths { ctx.Build(pctx, android.BuildParams{ @@ -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/java/plugin.go b/java/plugin.go index 731dfda00..51272981b 100644 --- a/java/plugin.go +++ b/java/plugin.go @@ -66,7 +66,10 @@ type pluginAttributes struct { // ConvertWithBp2build is used to convert android_app to Bazel. func (p *Plugin) ConvertWithBp2build(ctx android.TopDownMutatorContext) { pluginName := p.Name() - commonAttrs, bp2BuildInfo := p.convertLibraryAttrsBp2Build(ctx) + commonAttrs, bp2BuildInfo, supported := p.convertLibraryAttrsBp2Build(ctx) + if !supported { + return + } depLabels := bp2BuildInfo.DepLabels deps := depLabels.Deps diff --git a/java/sdk_library.go b/java/sdk_library.go index dbb2f0247..b1ddde093 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -387,6 +387,23 @@ var ( apiScopeModuleLib, apiScopeSystemServer, } + apiLibraryAdditionalProperties = map[string]struct { + FullApiSurfaceStubLib string + AdditionalApiContribution string + }{ + "legacy.i18n.module.platform.api": { + FullApiSurfaceStubLib: "legacy.core.platform.api.stubs", + AdditionalApiContribution: "i18n.module.public.api.stubs.source.api.contribution", + }, + "stable.i18n.module.platform.api": { + FullApiSurfaceStubLib: "stable.core.platform.api.stubs", + AdditionalApiContribution: "i18n.module.public.api.stubs.source.api.contribution", + }, + "conscrypt.module.platform.api": { + FullApiSurfaceStubLib: "stable.core.platform.api.stubs", + AdditionalApiContribution: "conscrypt.module.public.api.stubs.source.api.contribution", + }, + } ) var ( @@ -1513,6 +1530,29 @@ func (module *SdkLibrary) contributesToApiSurface(c android.Config) bool { return exists } +// The listed modules are the special java_sdk_libraries where apiScope.kind do not match the +// api surface that the module contribute to. For example, the public droidstubs and java_library +// do not contribute to the public api surface, but contributes to the core platform api surface. +// This method returns the full api surface stub lib that +// the generated java_api_library should depend on. +func (module *SdkLibrary) alternativeFullApiSurfaceStubLib() string { + if val, ok := apiLibraryAdditionalProperties[module.Name()]; ok { + return val.FullApiSurfaceStubLib + } + return "" +} + +// The listed modules' stubs contents do not match the corresponding txt files, +// but require additional api contributions to generate the full stubs. +// This method returns the name of the additional api contribution module +// for corresponding sdk_library modules. +func (module *SdkLibrary) apiLibraryAdditionalApiContribution() string { + if val, ok := apiLibraryAdditionalProperties[module.Name()]; ok { + return val.AdditionalApiContribution + } + return "" +} + func childModuleVisibility(childVisibility []string) []string { if childVisibility == nil { // No child visibility set. The child will use the visibility of the sdk_library. @@ -1778,7 +1818,7 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC mctx.CreateModule(DroidstubsFactory, &props).(*Droidstubs).CallHookIfAvailable(mctx) } -func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) { +func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope, alternativeFullApiSurfaceStub string) { props := struct { Name *string Visibility []string @@ -1801,13 +1841,22 @@ func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiContributions = append(apiContributions, module.stubsSourceModuleName(scope)+".api.contribution") scope = scope.extends } + if apiScope == apiScopePublic { + additionalApiContribution := module.apiLibraryAdditionalApiContribution() + if additionalApiContribution != "" { + apiContributions = append(apiContributions, additionalApiContribution) + } + } props.Api_contributions = apiContributions props.Libs = module.properties.Libs props.Libs = append(props.Libs, module.sdkLibraryProperties.Stub_only_libs...) props.Libs = append(props.Libs, "stub-annotations") props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs - props.Full_api_surface_stub = proptools.StringPtr(apiScope.kind.DefaultJavaLibraryName() + ".from-text") + props.Full_api_surface_stub = proptools.StringPtr(apiScope.kind.DefaultJavaLibraryName()) + if alternativeFullApiSurfaceStub != "" { + props.Full_api_surface_stub = proptools.StringPtr(alternativeFullApiSurfaceStub) + } // android_module_lib_stubs_current.from-text only comprises api contributions from art, conscrypt and i18n. // Thus, replace with android_module_lib_stubs_current_full.from-text, which comprises every api domains. @@ -2062,9 +2111,13 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont module.createStubsLibrary(mctx, scope) - contributesToApiSurface := module.contributesToApiSurface(mctx.Config()) + alternativeFullApiSurfaceStubLib := "" + if scope == apiScopePublic { + alternativeFullApiSurfaceStubLib = module.alternativeFullApiSurfaceStubLib() + } + contributesToApiSurface := module.contributesToApiSurface(mctx.Config()) || alternativeFullApiSurfaceStubLib != "" if contributesToApiSurface { - module.createApiLibrary(mctx, scope) + module.createApiLibrary(mctx, scope, alternativeFullApiSurfaceStubLib) } module.createTopLevelStubsLibrary(mctx, scope, contributesToApiSurface) diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index c22b9809b..118f8b68c 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -1449,17 +1449,17 @@ func TestJavaSdkLibrary_ApiLibrary(t *testing.T) { { scope: apiScopePublic, apiContributions: []string{"foo.stubs.source.api.contribution"}, - fullApiSurfaceStub: "android_stubs_current.from-text", + fullApiSurfaceStub: "android_stubs_current", }, { scope: apiScopeSystem, apiContributions: []string{"foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"}, - fullApiSurfaceStub: "android_system_stubs_current.from-text", + fullApiSurfaceStub: "android_system_stubs_current", }, { scope: apiScopeTest, apiContributions: []string{"foo.stubs.source.test.api.contribution", "foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"}, - fullApiSurfaceStub: "android_test_stubs_current.from-text", + fullApiSurfaceStub: "android_test_stubs_current", }, { scope: apiScopeModuleLib, diff --git a/python/bp2build.go b/python/bp2build.go index cd3f2a1a8..41e9f4974 100644 --- a/python/bp2build.go +++ b/python/bp2build.go @@ -73,7 +73,6 @@ func (m *PythonLibraryModule) makeArchVariantBaseAttributes(ctx android.TopDownM if !partitionedSrcs["proto"].IsEmpty() { protoInfo, _ := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, partitionedSrcs["proto"]) - protoLabel := bazel.Label{Label: ":" + protoInfo.Name} pyProtoLibraryName := m.Name() + "_py_proto" ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{ @@ -82,7 +81,7 @@ func (m *PythonLibraryModule) makeArchVariantBaseAttributes(ctx android.TopDownM }, android.CommonAttributes{ Name: pyProtoLibraryName, }, &bazelPythonProtoLibraryAttributes{ - Deps: bazel.MakeSingleLabelListAttribute(protoLabel), + Deps: bazel.MakeLabelListAttribute(protoInfo.Proto_libs), }) attrs.Deps.Add(bazel.MakeLabelAttribute(":" + pyProtoLibraryName)) @@ -223,7 +222,8 @@ func (p *PythonTestModule) ConvertWithBp2build(ctx android.TopDownMutatorContext props := bazel.BazelTargetModuleProperties{ // Use the native py_binary rule. - Rule_class: "py_test", + Rule_class: "py_test", + Bzl_load_location: "//build/bazel/rules/python:py_test.bzl", } ctx.CreateBazelTargetModule(props, android.CommonAttributes{ diff --git a/python/builder.go b/python/builder.go index 106649398..2553a7714 100644 --- a/python/builder.go +++ b/python/builder.go @@ -73,14 +73,14 @@ var ( precompile = pctx.AndroidStaticRule("precompilePython", blueprint.RuleParams{ Command: `LD_LIBRARY_PATH="$ldLibraryPath" ` + - `PYTHONPATH=$stdlibZip/internal/stdlib ` + + `PYTHONPATH=$stdlibZip/internal/$stdlibPkg ` + `$launcher build/soong/python/scripts/precompile_python.py $in $out`, CommandDeps: []string{ "$stdlibZip", "$launcher", "build/soong/python/scripts/precompile_python.py", }, - }, "stdlibZip", "launcher", "ldLibraryPath") + }, "stdlibZip", "stdlibPkg", "launcher", "ldLibraryPath") ) func init() { diff --git a/python/proto.go b/python/proto.go index 400e72c99..ad2b786e2 100644 --- a/python/proto.go +++ b/python/proto.go @@ -19,7 +19,8 @@ import ( ) func genProto(ctx android.ModuleContext, protoFile android.Path, flags android.ProtoFlags) android.Path { - srcsZipFile := android.PathForModuleGen(ctx, protoFile.Base()+".srcszip") + // Using protoFile.Base() would generate duplicate source errors in some cases, so we use Rel() instead + srcsZipFile := android.PathForModuleGen(ctx, protoFile.Rel()+".srcszip") outDir := srcsZipFile.ReplaceExtension(ctx, "tmp") depFile := srcsZipFile.ReplaceExtension(ctx, "srcszip.d") diff --git a/python/python.go b/python/python.go index 8fde638b4..6c837a888 100644 --- a/python/python.go +++ b/python/python.go @@ -169,6 +169,7 @@ type pythonDependency interface { getDataPathMappings() []pathMapping getSrcsZip() android.Path getPrecompiledSrcsZip() android.Path + getPkgPath() string } // getSrcsPathMappings gets this module's path mapping of src source path : runfiles destination @@ -191,6 +192,11 @@ func (p *PythonLibraryModule) getPrecompiledSrcsZip() android.Path { return p.precompiledSrcsZip } +// getPkgPath returns the pkg_path value +func (p *PythonLibraryModule) getPkgPath() string { + return String(p.properties.Pkg_path) +} + func (p *PythonLibraryModule) getBaseProperties() *BaseProperties { return &p.properties } @@ -370,7 +376,20 @@ func (p *PythonLibraryModule) AddDepsOnPythonLauncherAndStdlib(ctx android.Botto launcherSharedLibDeps = append(launcherSharedLibDeps, "libc++") case pyVersion3: - stdLib = "py3-stdlib" + var prebuiltStdLib bool + if targetForDeps.Os.Bionic() { + prebuiltStdLib = false + } else if ctx.Config().VendorConfig("cpython3").Bool("force_build_host") { + prebuiltStdLib = false + } else { + prebuiltStdLib = true + } + + if prebuiltStdLib { + stdLib = "py3-stdlib-prebuilt" + } else { + stdLib = "py3-stdlib" + } launcherModule = "py3-launcher" if autorun { @@ -461,14 +480,19 @@ func (p *PythonLibraryModule) genModulePathMappings(ctx android.ModuleContext, p destToPySrcs := make(map[string]string) destToPyData := make(map[string]string) + // Disable path checks for the stdlib, as it includes a "." in the version string + isInternal := proptools.BoolDefault(p.properties.Is_internal, false) + for _, s := range expandedSrcs { if s.Ext() != pyExt && s.Ext() != protoExt { ctx.PropertyErrorf("srcs", "found non (.py|.proto) file: %q!", s.String()) continue } runfilesPath := filepath.Join(pkgPath, s.Rel()) - if err := isValidPythonPath(runfilesPath); err != nil { - ctx.PropertyErrorf("srcs", err.Error()) + if !isInternal { + if err := isValidPythonPath(runfilesPath); err != nil { + ctx.PropertyErrorf("srcs", err.Error()) + } } if !checkForDuplicateOutputPath(ctx, destToPySrcs, runfilesPath, s.String(), p.Name(), p.Name()) { p.srcsPathMappings = append(p.srcsPathMappings, pathMapping{dest: runfilesPath, src: s}) @@ -591,13 +615,16 @@ func (p *PythonLibraryModule) precompileSrcs(ctx android.ModuleContext) android. // "cross compiling" for device here purely by virtue of host and device python bytecode // being the same. var stdLib android.Path + var stdLibPkg string var launcher android.Path - if ctx.ModuleName() == "py3-stdlib" || ctx.ModuleName() == "py2-stdlib" { + if proptools.BoolDefault(p.properties.Is_internal, false) { stdLib = p.srcsZip + stdLibPkg = p.getPkgPath() } else { ctx.VisitDirectDepsWithTag(hostStdLibTag, func(module android.Module) { if dep, ok := module.(pythonDependency); ok { stdLib = dep.getPrecompiledSrcsZip() + stdLibPkg = dep.getPkgPath() } }) } @@ -636,6 +663,7 @@ func (p *PythonLibraryModule) precompileSrcs(ctx android.ModuleContext) android. Description: "Precompile the python sources of " + ctx.ModuleName(), Args: map[string]string{ "stdlibZip": stdLib.String(), + "stdlibPkg": stdLibPkg, "launcher": launcher.String(), "ldLibraryPath": strings.Join(ldLibraryPath, ":"), }, diff --git a/python/tests/par_test.py b/python/tests/par_test.py index 1e03f1669..96b42ae83 100644 --- a/python/tests/par_test.py +++ b/python/tests/par_test.py @@ -33,6 +33,8 @@ if fileName.endswith('.pyc'): assert_equal("os.path.basename(__file__)", fileName, "par_test.py") archive = os.path.dirname(__file__) +major = sys.version_info.major +minor = sys.version_info.minor assert_equal("__package__", __package__, "") assert_equal("sys.argv[0]", sys.argv[0], archive) @@ -42,10 +44,11 @@ assert_equal("sys.prefix", sys.prefix, archive) assert_equal("__loader__.archive", __loader__.archive, archive) assert_equal("site.ENABLE_USER_SITE", site.ENABLE_USER_SITE, None) -assert_equal("len(sys.path)", len(sys.path), 3) +assert_equal("len(sys.path)", len(sys.path), 4) assert_equal("sys.path[0]", sys.path[0], archive) -assert_equal("sys.path[1]", sys.path[1], os.path.join(archive, "internal")) -assert_equal("sys.path[2]", sys.path[2], os.path.join(archive, "internal", "stdlib")) +assert_equal("sys.path[1]", sys.path[1], os.path.join(archive, "internal", f"python{major}{minor}.zip")) +assert_equal("sys.path[2]", sys.path[2], os.path.join(archive, "internal", f"python{major}.{minor}")) +assert_equal("sys.path[3]", sys.path[3], os.path.join(archive, "internal", f"python{major}.{minor}", "lib-dynload")) if os.getenv('ARGTEST', False): assert_equal("len(sys.argv)", len(sys.argv), 3) diff --git a/python/tests/py-cmd_test.py b/python/tests/py-cmd_test.py index c7ba0ab4b..8aed78289 100644 --- a/python/tests/py-cmd_test.py +++ b/python/tests/py-cmd_test.py @@ -55,22 +55,22 @@ assert_equal("sys.exec_prefix", sys.exec_prefix, sys.executable) assert_equal("sys.prefix", sys.prefix, sys.executable) assert_equal("site.ENABLE_USER_SITE", site.ENABLE_USER_SITE, None) -if sys.version_info[0] == 2: +major = sys.version_info.major +minor = sys.version_info.minor + +if major == 2: assert_equal("len(sys.path)", len(sys.path), 4) assert_equal("sys.path[0]", sys.path[0], os.path.abspath(os.path.dirname(__file__))) assert_equal("sys.path[1]", sys.path[1], "/extra") assert_equal("sys.path[2]", sys.path[2], os.path.join(sys.executable, "internal")) assert_equal("sys.path[3]", sys.path[3], os.path.join(sys.executable, "internal", "stdlib")) else: - assert_equal("len(sys.path)", len(sys.path), 8) + assert_equal("len(sys.path)", len(sys.path), 5) assert_equal("sys.path[0]", sys.path[0], os.path.abspath(os.path.dirname(__file__))) assert_equal("sys.path[1]", sys.path[1], "/extra") - assert_equal("sys.path[2]", sys.path[2], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + str(sys.version_info[1]) + '.zip')) - assert_equal("sys.path[3]", sys.path[3], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1]), '..')) - assert_equal("sys.path[4]", sys.path[4], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1]))) - assert_equal("sys.path[5]", sys.path[5], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1]), 'lib-dynload')) - assert_equal("sys.path[6]", sys.path[6], os.path.join(sys.executable, "internal")) - assert_equal("sys.path[7]", sys.path[7], os.path.join(sys.executable, "internal", "stdlib")) + assert_equal("sys.path[2]", sys.path[2], os.path.join(sys.executable, 'internal', 'python' + str(sys.version_info[0]) + str(sys.version_info[1]) + '.zip')) + assert_equal("sys.path[3]", sys.path[3], os.path.join(sys.executable, 'internal', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1]))) + assert_equal("sys.path[4]", sys.path[4], os.path.join(sys.executable, 'internal', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1]), 'lib-dynload')) if failed: sys.exit(1) 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/binary_test.go b/rust/binary_test.go index dd4f99314..fc4c56037 100644 --- a/rust/binary_test.go +++ b/rust/binary_test.go @@ -21,6 +21,27 @@ import ( "android/soong/android" ) +// Test that rustlibs default linkage is always rlib for host binaries. +func TestBinaryHostLinkage(t *testing.T) { + ctx := testRust(t, ` + rust_binary_host { + name: "fizz-buzz", + srcs: ["foo.rs"], + rustlibs: ["libfoo"], + } + rust_library { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + host_supported: true, + } + `) + fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module) + if !android.InList("libfoo.rlib-std", fizzBuzz.Properties.AndroidMkRlibs) { + t.Errorf("rustlibs dependency libfoo should be an rlib dep for host binaries") + } +} + // Test that rustlibs default linkage is correct for binaries. func TestBinaryLinkage(t *testing.T) { ctx := testRust(t, ` @@ -54,6 +75,12 @@ func TestBinaryLinkage(t *testing.T) { if !android.InList("libfoo", fizzBuzzDevice.Properties.AndroidMkDylibs) { t.Errorf("rustlibs dependency libfoo should be an dylib dep for device modules") } + + rlibLinkDevice := ctx.ModuleForTests("rlib_linked", "android_arm64_armv8-a").Module().(*Module) + + if !android.InList("libfoo.rlib-std", rlibLinkDevice.Properties.AndroidMkRlibs) { + t.Errorf("rustlibs dependency libfoo should be an rlib dep for device modules when prefer_rlib is set") + } } // Test that prefer_rlib links in libstd statically as well as rustlibs. diff --git a/rust/bindgen.go b/rust/bindgen.go index 96645b075..407f2754f 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 != "" { @@ -61,15 +61,18 @@ var ( "${cc_config.ClangBase}/${bindgenHostPrebuiltTag}/${bindgenClangVersion}/${bindgenClangLibdir}") //TODO(ivanlozano) Switch this to RuleBuilder + // + //TODO Pass the flag files directly to bindgen e.g. with @file when it supports that. + //See https://github.com/rust-lang/rust-bindgen/issues/2508. bindgen = pctx.AndroidStaticRule("bindgen", blueprint.RuleParams{ Command: "CLANG_PATH=$bindgenClang LIBCLANG_PATH=$bindgenLibClang RUSTFMT=${config.RustBin}/rustfmt " + - "$cmd $flags $in -o $out -- -MD -MF $out.d $cflags", + "$cmd $flags $$(cat $flagfiles) $in -o $out -- -MD -MF $out.d $cflags", CommandDeps: []string{"$cmd"}, Deps: blueprint.DepsGCC, Depfile: "$out.d", }, - "cmd", "flags", "cflags") + "cmd", "flags", "flagfiles", "cflags") ) func init() { @@ -90,6 +93,9 @@ type BindgenProperties struct { // list of bindgen-specific flags and options Bindgen_flags []string `android:"arch_variant"` + // list of files containing extra bindgen flags + Bindgen_flag_files []string `android:"arch_variant"` + // module name of a custom binary/script which should be used instead of the 'bindgen' binary. This custom // binary must expect arguments in a similar fashion to bindgen, e.g. // @@ -216,6 +222,14 @@ func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) andr bindgenFlags := defaultBindgenFlags bindgenFlags = append(bindgenFlags, esc(b.Properties.Bindgen_flags)...) + // cat reads from stdin if its command line is empty, + // so we pass in /dev/null if there are no other flag files + bindgenFlagFiles := []string{"/dev/null"} + for _, flagFile := range b.Properties.Bindgen_flag_files { + bindgenFlagFiles = append(bindgenFlagFiles, android.PathForModuleSrc(ctx, flagFile).String()) + implicits = append(implicits, android.PathForModuleSrc(ctx, flagFile)) + } + wrapperFile := android.OptionalPathForModuleSrc(ctx, b.Properties.Wrapper_src) if !wrapperFile.Valid() { ctx.PropertyErrorf("wrapper_src", "invalid path to wrapper source") @@ -247,7 +261,7 @@ func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) andr var cmd, cmdDesc string if b.Properties.Custom_bindgen != "" { - cmd = ctx.GetDirectDepWithTag(b.Properties.Custom_bindgen, customBindgenDepTag).(*Module).HostToolPath().String() + cmd = ctx.GetDirectDepWithTag(b.Properties.Custom_bindgen, customBindgenDepTag).(android.HostToolProvider).HostToolPath().String() cmdDesc = b.Properties.Custom_bindgen } else { cmd = "$bindgenCmd" @@ -261,9 +275,10 @@ func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) andr Input: wrapperFile.Path(), Implicits: implicits, Args: map[string]string{ - "cmd": cmd, - "flags": strings.Join(bindgenFlags, " "), - "cflags": strings.Join(cflags, " "), + "cmd": cmd, + "flags": strings.Join(bindgenFlags, " "), + "flagfiles": strings.Join(bindgenFlagFiles, " "), + "cflags": strings.Join(cflags, " "), }, }) @@ -279,7 +294,7 @@ func (b *bindgenDecorator) SourceProviderProps() []interface{} { // rust_bindgen generates Rust FFI bindings to C libraries using bindgen given a wrapper header as the primary input. // Bindgen has a number of flags to control the generated source, and additional flags can be passed to clang to ensure // the header and generated source is appropriately handled. It is recommended to add it as a dependency in the -// rlibs, dylibs or rustlibs property. It may also be added in the srcs property for external crates, using the ":" +// rlibs or rustlibs property. It may also be added in the srcs property for external crates, using the ":" // prefix. func RustBindgenFactory() android.Module { module, _ := NewRustBindgen(android.HostAndDeviceSupported) diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go index af04cfc89..12cdb3cb4 100644 --- a/rust/bindgen_test.go +++ b/rust/bindgen_test.go @@ -168,3 +168,28 @@ func TestBindgenDisallowedFlags(t *testing.T) { } `) } + +func TestBindgenFlagFile(t *testing.T) { + ctx := testRust(t, ` + rust_bindgen { + name: "libbindgen", + wrapper_src: "src/any.h", + crate_name: "bindgen", + stem: "libbindgen", + source_stem: "bindings", + bindgen_flag_files: [ + "flag_file.txt", + ], + } + `) + libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs") + + if !strings.Contains(libbindgen.Args["flagfiles"], "/dev/null") { + t.Errorf("missing /dev/null in rust_bindgen rule: flags %#v", libbindgen.Args["flagfiles"]) + } + if !strings.Contains(libbindgen.Args["flagfiles"], "flag_file.txt") { + t.Errorf("missing bindgen flags file in rust_bindgen rule: flags %#v", libbindgen.Args["flagfiles"]) + } + // TODO: The best we can do right now is check $flagfiles. Once bindgen.go switches to RuleBuilder, + // we may be able to check libbinder.RuleParams.Command to see if it contains $(cat /dev/null flag_file.txt) +} diff --git a/rust/builder.go b/rust/builder.go index c31bc88d1..b1f049d15 100644 --- a/rust/builder.go +++ b/rust/builder.go @@ -45,9 +45,9 @@ var ( "rustcFlags", "libFlags", "envVars") rustLink = pctx.AndroidStaticRule("rustLink", blueprint.RuleParams{ - Command: "${config.RustLinker} -o $out ${crtBegin} ${config.RustLinkerArgs} @$in ${linkFlags} ${crtEnd}", + Command: "${config.RustLinker} -o $out ${crtBegin} ${earlyLinkFlags} @$in ${linkFlags} ${crtEnd}", }, - "linkFlags", "crtBegin", "crtEnd") + "earlyLinkFlags", "linkFlags", "crtBegin", "crtEnd") _ = pctx.SourcePathVariable("rustdocCmd", "${config.RustBin}/rustdoc") rustdoc = pctx.AndroidStaticRule("rustdoc", @@ -228,11 +228,26 @@ func rustEnvVars(ctx ModuleContext, deps PathDeps) []string { pkgVersion := ctx.RustModule().compiler.CargoPkgVersion() if pkgVersion != "" { envVars = append(envVars, "CARGO_PKG_VERSION="+pkgVersion) + + // Ensure the version is in the form of "x.y.z" (approximately semver compliant). + // + // For our purposes, we don't care to enforce that these are integers since they may + // include other characters at times (e.g. sometimes the patch version is more than an integer). + if strings.Count(pkgVersion, ".") == 2 { + var semver_parts = strings.Split(pkgVersion, ".") + envVars = append(envVars, "CARGO_PKG_VERSION_MAJOR="+semver_parts[0]) + envVars = append(envVars, "CARGO_PKG_VERSION_MINOR="+semver_parts[1]) + envVars = append(envVars, "CARGO_PKG_VERSION_PATCH="+semver_parts[2]) + } } } envVars = append(envVars, "AR=${cc_config.ClangBin}/llvm-ar") + if ctx.Darwin() { + envVars = append(envVars, "ANDROID_RUST_DARWIN=true") + } + return envVars } @@ -243,6 +258,7 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl var implicits, linkImplicits, linkOrderOnly android.Paths var output buildOutput var rustcFlags, linkFlags []string + var earlyLinkFlags string output.outputFile = outputFile crateName := ctx.RustModule().CrateName() @@ -281,6 +297,10 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl } // Collect linker flags + if !ctx.Darwin() { + earlyLinkFlags = "-Wl,--as-needed" + } + linkFlags = append(linkFlags, flags.GlobalLinkFlags...) linkFlags = append(linkFlags, flags.LinkFlags...) @@ -380,9 +400,10 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl Implicits: linkImplicits, OrderOnly: linkOrderOnly, Args: map[string]string{ - "linkFlags": strings.Join(linkFlags, " "), - "crtBegin": strings.Join(deps.CrtBegin.Strings(), " "), - "crtEnd": strings.Join(deps.CrtEnd.Strings(), " "), + "earlyLinkFlags": earlyLinkFlags, + "linkFlags": strings.Join(linkFlags, " "), + "crtBegin": strings.Join(deps.CrtBegin.Strings(), " "), + "crtEnd": strings.Join(deps.CrtEnd.Strings(), " "), }, }) } diff --git a/rust/compiler.go b/rust/compiler.go index 06ae12f79..e6a7a9356 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -91,10 +91,8 @@ type BaseCompilerProperties struct { // list of rust rlib crate dependencies Rlibs []string `android:"arch_variant"` - // list of rust dylib crate dependencies - Dylibs []string `android:"arch_variant"` - - // list of rust automatic crate dependencies + // list of rust automatic crate dependencies. + // Rustlibs linkage is rlib for host targets and dylib for device targets. Rustlibs []string `android:"arch_variant"` // list of rust proc_macro crate dependencies @@ -320,6 +318,15 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flag flags.LinkFlags = append(flags.LinkFlags, cc.RpathFlags(ctx)...) } + if !ctx.toolchain().Bionic() && ctx.Os() != android.LinuxMusl && !ctx.Windows() { + // Add -ldl, -lpthread, -lm and -lrt to host builds to match the default behavior of device + // builds. This is irrelevant for the Windows target as these are Posix specific. + flags.LinkFlags = append(flags.LinkFlags, + "-ldl", + "-lpthread", + "-lm", + ) + } return flags } @@ -359,7 +366,6 @@ func (compiler *baseCompiler) strippedOutputFilePath() android.OptionalPath { func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...) - deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...) deps.Rustlibs = append(deps.Rustlibs, compiler.Properties.Rustlibs...) deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...) deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...) 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..86eb2d1cb 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{ @@ -102,7 +102,6 @@ func init() { pctx.ImportAs("cc_config", "android/soong/cc/config") pctx.StaticVariable("RustLinker", "${cc_config.ClangBin}/clang++") - pctx.StaticVariable("RustLinkerArgs", "-Wl,--as-needed") pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " ")) diff --git a/rust/fuzz.go b/rust/fuzz.go index c2b940525..235f51779 100644 --- a/rust/fuzz.go +++ b/rust/fuzz.go @@ -25,6 +25,7 @@ import ( func init() { android.RegisterModuleType("rust_fuzz", RustFuzzFactory) + android.RegisterModuleType("rust_fuzz_host", RustFuzzHostFactory) } type fuzzDecorator struct { @@ -43,6 +44,11 @@ func RustFuzzFactory() android.Module { return module.Init() } +func RustFuzzHostFactory() android.Module { + module, _ := NewRustFuzz(android.HostSupported) + return module.Init() +} + func NewRustFuzz(hod android.HostOrDeviceSupported) (*Module, *fuzzDecorator) { module, binary := NewRustBinary(hod) fuzz := &fuzzDecorator{ diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go index 0aecf617e..ee28c6d3a 100644 --- a/rust/fuzz_test.go +++ b/rust/fuzz_test.go @@ -34,6 +34,10 @@ func TestRustFuzz(t *testing.T) { srcs: ["foo.rs"], rustlibs: ["libtest_fuzzing"], } + rust_fuzz_host { + name: "host_fuzzer", + srcs: ["foo.rs"], + } `) // Check that appropriate dependencies are added and that the rustlib linkage is correct. @@ -50,7 +54,13 @@ func TestRustFuzz(t *testing.T) { if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov-module'") || !strings.Contains(fuzz_libtest.Args["rustcFlags"], "--cfg fuzzing") { t.Errorf("rust_fuzz module does not contain the expected flags (sancov-module, cfg fuzzing).") + } + // Check that host modules support fuzzing. + host_fuzzer := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc") + if !strings.Contains(host_fuzzer.Args["rustcFlags"], "-C passes='sancov-module'") || + !strings.Contains(host_fuzzer.Args["rustcFlags"], "--cfg fuzzing") { + t.Errorf("rust_fuzz_host module does not contain the expected flags (sancov-module, cfg fuzzing).") } // Check that dependencies have 'fuzzer' variants produced for them as well. 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..419fcfca2 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 @@ -473,7 +466,15 @@ func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) F library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...) } if library.shared() { - flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx)) + if ctx.Darwin() { + flags.LinkFlags = append( + flags.LinkFlags, + "-dynamic_lib", + "-install_name @rpath/"+library.sharedLibFilename(ctx), + ) + } else { + flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx)) + } } return flags @@ -693,24 +694,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 +730,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/protobuf.go b/rust/protobuf.go index 0cf6e8c97..a14ebeaab 100644 --- a/rust/protobuf.go +++ b/rust/protobuf.go @@ -243,7 +243,7 @@ func (proto *protobufDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) D // rust_protobuf generates protobuf rust code from the provided proto file. This uses the protoc-gen-rust plugin for // protoc. Additional flags to the protoc command can be passed via the proto_flags property. This module type will -// create library variants that can be used as a crate dependency by adding it to the rlibs, dylibs, and rustlibs +// create library variants that can be used as a crate dependency by adding it to the rlibs and rustlibs // properties of other modules. func RustProtobufFactory() android.Module { module, _ := NewRustProtobuf(android.HostAndDeviceSupported) diff --git a/rust/rust.go b/rust/rust.go index e524c9fb6..fc8db8655 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 { @@ -601,6 +613,7 @@ func DefaultsFactory(props ...interface{}) android.Module { &cc.RustBindgenClangProperties{}, &ClippyProperties{}, &SanitizeProperties{}, + &fuzz.FuzzProperties{}, ) android.InitDefaultsModule(module) @@ -1212,6 +1225,11 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if _, exists := skipModuleList[depName]; exists { return } + + if depTag == android.DarwinUniversalVariantTag { + return + } + if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() { //Handle Rust Modules makeLibName := rustMakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName) @@ -1225,6 +1243,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 +1254,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) @@ -1290,12 +1312,17 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } } linkObject := ccDep.OutputFile() - linkPath := linkPathFromFilePath(linkObject.Path()) - if !linkObject.Valid() { - ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName()) + if !ctx.Config().AllowMissingDependencies() { + ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName()) + } else { + ctx.AddMissingDependencies([]string{depName}) + } + return } + linkPath := linkPathFromFilePath(linkObject.Path()) + exportDep := false switch { case cc.IsStaticDepTag(depTag): @@ -1340,6 +1367,14 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // Re-get linkObject as ChooseStubOrImpl actually tells us which // object (either from stub or non-stub) to use. linkObject = android.OptionalPathForPath(sharedLibraryInfo.SharedLibrary) + if !linkObject.Valid() { + if !ctx.Config().AllowMissingDependencies() { + ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName()) + } else { + ctx.AddMissingDependencies([]string{depName}) + } + return + } linkPath = linkPathFromFilePath(linkObject.Path()) depPaths.linkDirs = append(depPaths.linkDirs, linkPath) @@ -1518,10 +1553,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 +1571,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 +1587,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 +1672,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..704bfe785 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 { @@ -228,11 +232,6 @@ func TestDepsTracking(t *testing.T) { srcs: ["foo.rs"], crate_name: "shared", } - rust_library_host_dylib { - name: "libdylib", - srcs: ["foo.rs"], - crate_name: "dylib", - } rust_library_host_rlib { name: "librlib", srcs: ["foo.rs"], @@ -248,7 +247,6 @@ func TestDepsTracking(t *testing.T) { } rust_binary_host { name: "fizz-buzz", - dylibs: ["libdylib"], rlibs: ["librlib"], proc_macros: ["libpm"], static_libs: ["libstatic"], @@ -261,10 +259,6 @@ func TestDepsTracking(t *testing.T) { rustLink := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustLink") // Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up. - if !android.InList("libdylib", module.Properties.AndroidMkDylibs) { - t.Errorf("Dylib dependency not detected (dependency missing from AndroidMkDylibs)") - } - if !android.InList("librlib.rlib-std", module.Properties.AndroidMkRlibs) { t.Errorf("Rlib dependency not detected (dependency missing from AndroidMkRlibs)") } diff --git a/rust/sanitize.go b/rust/sanitize.go index 0f7cf6e5f..cc19e6e61 100644 --- a/rust/sanitize.go +++ b/rust/sanitize.go @@ -209,8 +209,8 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { } // TODO:(b/178369775) - // For now sanitizing is only supported on devices - if ctx.Os() == android.Android && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap) || Bool(s.Fuzzer)) { + // For now sanitizing is only supported on non-windows targets + if ctx.Os() != android.Windows && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap) || Bool(s.Fuzzer)) { sanitize.Properties.SanitizerEnabled = true } } @@ -223,12 +223,22 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags, deps PathDeps) ( if !sanitize.Properties.SanitizerEnabled { return flags, deps } + if Bool(sanitize.Properties.Sanitize.Fuzzer) { flags.RustFlags = append(flags.RustFlags, fuzzerFlags...) - } else if Bool(sanitize.Properties.Sanitize.Hwaddress) { + } + + if Bool(sanitize.Properties.Sanitize.Hwaddress) { flags.RustFlags = append(flags.RustFlags, hwasanFlags...) - } else if Bool(sanitize.Properties.Sanitize.Address) { + } + + if Bool(sanitize.Properties.Sanitize.Address) { flags.RustFlags = append(flags.RustFlags, asanFlags...) + if ctx.Host() { + // -nodefaultlibs (provided with libc++) prevents the driver from linking + // libraries needed with -fsanitize=address. http://b/18650275 (WAI) + flags.LinkFlags = append(flags.LinkFlags, []string{"-Wl,--no-as-needed"}...) + } } return flags, deps } @@ -267,14 +277,19 @@ func rustSanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { var depTag blueprint.DependencyTag var deps []string - if mod.IsSanitizerEnabled(cc.Asan) || - (mod.IsSanitizerEnabled(cc.Fuzzer) && (mctx.Arch().ArchType != android.Arm64 || !mctx.Os().Bionic())) { - variations = append(variations, - blueprint.Variation{Mutator: "link", Variation: "shared"}) - depTag = cc.SharedDepTag() - deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")} - } else if mod.IsSanitizerEnabled(cc.Hwasan) || - (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType == android.Arm64 && mctx.Os().Bionic()) { + if mod.IsSanitizerEnabled(cc.Asan) { + if mod.Host() { + variations = append(variations, + blueprint.Variation{Mutator: "link", Variation: "static"}) + depTag = cc.StaticDepTag(false) + deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan.static")} + } else { + variations = append(variations, + blueprint.Variation{Mutator: "link", Variation: "shared"}) + depTag = cc.SharedDepTag() + deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")} + } + } else if mod.IsSanitizerEnabled(cc.Hwasan) { // TODO(b/204776996): HWASan for static Rust binaries isn't supported yet. if binary, ok := mod.compiler.(binaryInterface); ok { if binary.staticallyLinked() { @@ -388,7 +403,8 @@ func (sanitize *sanitize) AndroidMk(ctx AndroidMkContext, entries *android.Andro } func (mod *Module) SanitizerSupported(t cc.SanitizerType) bool { - if mod.Host() { + // Sanitizers are not supported on Windows targets. + if mod.Os() == android.Windows { return false } switch t { @@ -414,7 +430,8 @@ func (mod *Module) IsSanitizerEnabled(t cc.SanitizerType) bool { } func (mod *Module) IsSanitizerExplicitlyDisabled(t cc.SanitizerType) bool { - if mod.Host() { + // Sanitizers are not supported on Windows targets. + if mod.Os() == android.Windows { return true } 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/testing.go b/rust/testing.go index 7f3056954..3fe751e17 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -182,6 +182,7 @@ func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) { ctx.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory) ctx.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory) ctx.RegisterModuleType("rust_fuzz", RustFuzzFactory) + ctx.RegisterModuleType("rust_fuzz_host", RustFuzzHostFactory) ctx.RegisterModuleType("rust_ffi", RustFFIFactory) ctx.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory) ctx.RegisterModuleType("rust_ffi_static", RustFFIStaticFactory) 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/mkcratersp.py b/scripts/mkcratersp.py index 86b4aa3fb..6ef01ebcc 100755 --- a/scripts/mkcratersp.py +++ b/scripts/mkcratersp.py @@ -48,6 +48,8 @@ for i, arg in enumerate(sys.argv): linkdirs.append(sys.argv[i+1]) if arg.startswith('-l') or arg == '-shared': libs.append(arg) + if os.getenv('ANDROID_RUST_DARWIN') and (arg == '-dylib' or arg == '-dynamiclib'): + libs.append(arg) if arg.startswith('-Wl,--version-script='): version_script = arg[21:] if arg[0] == '-': @@ -64,9 +66,13 @@ create_archive(f'{out}.whole.a', objects, []) create_archive(f'{out}.a', [], temp_archives) with open(out, 'w') as f: - print(f'-Wl,--whole-archive', file=f) - print(f'{out}.whole.a', file=f) - print(f'-Wl,--no-whole-archive', file=f) + if os.getenv("ANDROID_RUST_DARWIN"): + print(f'-force_load', file=f) + print(f'{out}.whole.a', file=f) + else: + print(f'-Wl,--whole-archive', file=f) + print(f'{out}.whole.a', file=f) + print(f'-Wl,--no-whole-archive', file=f) print(f'{out}.a', file=f) for a in archives: print(a, file=f) 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_fmt/format.go b/starlark_fmt/format.go index 42095075c..0224bcf93 100644 --- a/starlark_fmt/format.go +++ b/starlark_fmt/format.go @@ -16,6 +16,7 @@ package starlark_fmt import ( "fmt" + "reflect" "sort" "strconv" "strings" @@ -33,6 +34,72 @@ func Indention(level int) string { return strings.Repeat(" ", level*indent) } +func PrintAny(value any, indentLevel int) string { + return printAnyRecursive(reflect.ValueOf(value), indentLevel) +} + +func printAnyRecursive(value reflect.Value, indentLevel int) string { + switch value.Type().Kind() { + case reflect.String: + val := value.String() + if strings.Contains(val, "\"") || strings.Contains(val, "\n") { + return `'''` + val + `'''` + } + return `"` + val + `"` + case reflect.Bool: + if value.Bool() { + return "True" + } else { + return "False" + } + case reflect.Int: + return fmt.Sprintf("%d", value.Int()) + case reflect.Slice: + if value.Len() == 0 { + return "[]" + } else if value.Len() == 1 { + return "[" + printAnyRecursive(value.Index(0), indentLevel) + "]" + } + list := make([]string, 0, value.Len()+2) + list = append(list, "[") + innerIndent := Indention(indentLevel + 1) + for i := 0; i < value.Len(); i++ { + list = append(list, innerIndent+printAnyRecursive(value.Index(i), indentLevel+1)+`,`) + } + list = append(list, Indention(indentLevel)+"]") + return strings.Join(list, "\n") + case reflect.Map: + if value.Len() == 0 { + return "{}" + } + items := make([]string, 0, value.Len()) + for _, key := range value.MapKeys() { + items = append(items, fmt.Sprintf(`%s%s: %s,`, Indention(indentLevel+1), printAnyRecursive(key, indentLevel+1), printAnyRecursive(value.MapIndex(key), indentLevel+1))) + } + sort.Strings(items) + return fmt.Sprintf(`{ +%s +%s}`, strings.Join(items, "\n"), Indention(indentLevel)) + case reflect.Struct: + if value.NumField() == 0 { + return "struct()" + } + items := make([]string, 0, value.NumField()+2) + items = append(items, "struct(") + for i := 0; i < value.NumField(); i++ { + if value.Type().Field(i).Anonymous { + panic("anonymous fields aren't supported") + } + name := value.Type().Field(i).Name + items = append(items, fmt.Sprintf(`%s%s = %s,`, Indention(indentLevel+1), name, printAnyRecursive(value.Field(i), indentLevel+1))) + } + items = append(items, Indention(indentLevel)+")") + return strings.Join(items, "\n") + default: + panic("Unhandled kind: " + value.Kind().String()) + } +} + // PrintBool returns a Starlark compatible bool string. func PrintBool(item bool) string { if item { 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/sysprop/sysprop_library.go b/sysprop/sysprop_library.go index 0edbb7c37..a2c0fb731 100644 --- a/sysprop/sysprop_library.go +++ b/sysprop/sysprop_library.go @@ -24,6 +24,7 @@ import ( "sync" "android/soong/bazel" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -410,7 +411,7 @@ type ccLibraryProperties struct { Apex_available []string Min_sdk_version *string Bazel_module struct { - Bp2build_available *bool + Label *string } } @@ -428,6 +429,9 @@ type javaLibraryProperties struct { SyspropPublicStub string Apex_available []string Min_sdk_version *string + Bazel_module struct { + Bp2build_available *bool + } } func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { @@ -473,6 +477,14 @@ func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { "Unknown value %s: must be one of Platform, Vendor or Odm", m.Owner()) } + var label *string + if b, ok := ctx.Module().(android.Bazelable); ok && b.ShouldConvertWithBp2build(ctx) { + // TODO: b/295566168 - this will need to change once build files are checked in to account for + // checked in modules in mixed builds + label = proptools.StringPtr( + fmt.Sprintf("//%s:%s", ctx.ModuleDir(), m.CcImplementationModuleName())) + } + // Generate a C++ implementation library. // cc_library can receive *.sysprop files as their srcs, generating sources itself. ccProps := ccLibraryProperties{} @@ -492,11 +504,7 @@ func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { ccProps.Host_supported = m.properties.Host_supported ccProps.Apex_available = m.ApexProperties.Apex_available ccProps.Min_sdk_version = m.properties.Cpp.Min_sdk_version - // A Bazel macro handles this, so this module does not need to be handled - // in bp2build - // TODO(b/237810289) perhaps do something different here so that we aren't - // also disabling these modules in mixed builds - ccProps.Bazel_module.Bp2build_available = proptools.BoolPtr(false) + ccProps.Bazel_module.Label = label ctx.CreateModule(cc.LibraryFactory, &ccProps) scope := "internal" @@ -541,6 +549,11 @@ func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { SyspropPublicStub: publicStub, Apex_available: m.ApexProperties.Apex_available, Min_sdk_version: m.properties.Java.Min_sdk_version, + Bazel_module: struct { + Bp2build_available *bool + }{ + Bp2build_available: proptools.BoolPtr(false), + }, }) if publicStub != "" { @@ -558,6 +571,11 @@ func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { Sdk_version: proptools.StringPtr("core_current"), Libs: []string{javaSyspropStub}, Stem: proptools.StringPtr(m.BaseModuleName()), + Bazel_module: struct { + Bp2build_available *bool + }{ + Bp2build_available: proptools.BoolPtr(false), + }, }) } 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..f3db76f8b 100644 --- a/tests/lib.sh +++ b/tests/lib.sh @@ -52,6 +52,10 @@ function copy_directory { cp -R "$REAL_TOP/$dir" "$MOCK_TOP/$parent" } +function delete_directory { + rm -rf "$MOCK_TOP/$1" +} + function symlink_file { local file="$1" @@ -138,6 +142,9 @@ function create_mock_bazel { copy_directory build/bazel copy_directory build/bazel_common_rules + # This requires pulling more tools into the mock top to build partitions + delete_directory build/bazel/examples/partitions + symlink_directory packages/modules/common/build symlink_directory prebuilts/bazel symlink_directory prebuilts/clang @@ -147,6 +154,8 @@ 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_python + 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..6b9ff8b93 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. @@ -22,7 +22,5 @@ TEST_BAZEL=true extra_build_params=--bazel-mode-staging "$TOP/build/soong/tests/ "$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_arm" "armv7-a" "$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_cf_arm64_phone" "armv8-a" "cortex-a53" -"$TOP/build/soong/tests/sbom_test.sh" - "$TOP/build/bazel/ci/b_test.sh" diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh index 19987f204..9801a8e4f 100755 --- a/tests/sbom_test.sh +++ b/tests/sbom_test.sh @@ -85,32 +85,32 @@ 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[vendor]="\ + -I /vendor/lib64/libkeystore2_crypto.so \ + -I /vendor/lib64/libvsock_utils.so" diff_excludes[system]="\ - -I /bin \ - -I /bugreports \ - -I /cache \ - -I /d \ - -I /etc \ - -I /init \ - -I /odm/app \ - -I /odm/bin \ - -I /odm_dlkm/etc \ - -I /odm/etc \ - -I /odm/firmware \ - -I /odm/framework \ - -I /odm/lib \ - -I /odm/lib64 \ - -I /odm/overlay \ - -I /odm/priv-app \ - -I /odm/usr \ - -I /sdcard \ + -I /system/bin/assemble_cvd \ + -I /system/bin/console_forwarder \ + -I /system/bin/kernel_log_monitor \ + -I /system/bin/logcat_receiver \ + -I /system/bin/mkenvimage_slim \ + -I /system/bin/run_cvd \ + -I /system/bin/simg2img \ + -I /system/bin/log_tee \ -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 \ @@ -124,8 +124,7 @@ function test_sbom_aosp_cf_x86_64_phone { -I /system/lib64/vndk-sp-29 \ -I /system/lib/vndk-29 \ -I /system/lib/vndk-sp-29 \ - -I /system/usr/icu \ - -I /vendor_dlkm/etc" + -I /system/usr/icu" # 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. @@ -219,8 +218,104 @@ function test_sbom_aosp_cf_x86_64_phone { diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name" done + verify_package_verification_code "$product_out/sbom.spdx" + + # Teardown + cleanup "${out_dir}" +} + +function verify_package_verification_code { + local sbom_file="$1"; shift + + local -a file_checksums + local package_product_found= + while read -r line; + do + if grep -q 'PackageVerificationCode' <<<"$line" + then + package_product_found=true + fi + if [ -n "$package_product_found" ] + then + if grep -q 'FileChecksum' <<< "$line" + then + checksum=$(echo $line | sed 's/^.*: //') + file_checksums+=("$checksum") + fi + fi + done <<< "$(grep -E 'PackageVerificationCode|FileChecksum' $sbom_file)" + IFS=$'\n' file_checksums=($(sort <<<"${file_checksums[*]}")); unset IFS + IFS= expected_package_verification_code=$(printf "${file_checksums[*]}" | sha1sum | sed 's/[[:space:]]*-//'); unset IFS + + actual_package_verification_code=$(grep PackageVerificationCode $sbom_file | sed 's/PackageVerificationCode: //g') + if [ $actual_package_verification_code = $expected_package_verification_code ] + then + echo "Package verification code is correct." + else + echo "Unexpected package verification code." + exit 1 + fi +} + +function test_sbom_unbundled_apex { + # Setup + out_dir="$(setup)" + + # 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
\ No newline at end of file +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..5d1505abc 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -15,7 +15,6 @@ package build import ( - "context" "encoding/json" "errors" "fmt" @@ -40,9 +39,6 @@ import ( const ( envConfigDir = "vendor/google/tools/soong_config" jsonSuffix = "json" - - configFetcher = "vendor/google/tools/soong/expconfigfetcher" - envConfigFetchTimeout = 20 * time.Second ) var ( @@ -174,87 +170,6 @@ func checkTopDir(ctx Context) { } } -// fetchEnvConfig optionally fetches a configuration file that can then subsequently be -// loaded into Soong environment to control certain aspects of build behavior (e.g., enabling RBE). -// If a configuration file already exists on disk, the fetch is run in the background -// so as to NOT block the rest of the build execution. -func fetchEnvConfig(ctx Context, config *configImpl, envConfigName string) error { - configName := envConfigName + "." + jsonSuffix - expConfigFetcher := &smpb.ExpConfigFetcher{Filename: &configName} - defer func() { - ctx.Metrics.ExpConfigFetcher(expConfigFetcher) - }() - if !config.GoogleProdCredsExist() { - status := smpb.ExpConfigFetcher_MISSING_GCERT - expConfigFetcher.Status = &status - return nil - } - - s, err := os.Stat(configFetcher) - if err != nil { - if os.IsNotExist(err) { - return nil - } - return err - } - if s.Mode()&0111 == 0 { - status := smpb.ExpConfigFetcher_ERROR - expConfigFetcher.Status = &status - return fmt.Errorf("configuration fetcher binary %v is not executable: %v", configFetcher, s.Mode()) - } - - configExists := false - outConfigFilePath := filepath.Join(config.OutDir(), configName) - if _, err := os.Stat(outConfigFilePath); err == nil { - configExists = true - } - - tCtx, cancel := context.WithTimeout(ctx, envConfigFetchTimeout) - fetchStart := time.Now() - cmd := exec.CommandContext(tCtx, configFetcher, "-output_config_dir", config.OutDir(), - "-output_config_name", configName) - if err := cmd.Start(); err != nil { - status := smpb.ExpConfigFetcher_ERROR - expConfigFetcher.Status = &status - return err - } - - fetchCfg := func() error { - if err := cmd.Wait(); err != nil { - status := smpb.ExpConfigFetcher_ERROR - expConfigFetcher.Status = &status - return err - } - fetchEnd := time.Now() - expConfigFetcher.Micros = proto.Uint64(uint64(fetchEnd.Sub(fetchStart).Microseconds())) - expConfigFetcher.Filename = proto.String(outConfigFilePath) - - if _, err := os.Stat(outConfigFilePath); err != nil { - status := smpb.ExpConfigFetcher_NO_CONFIG - expConfigFetcher.Status = &status - return err - } - status := smpb.ExpConfigFetcher_CONFIG - expConfigFetcher.Status = &status - return nil - } - - // If a config file does not exist, wait for the config file to be fetched. Otherwise - // fetch the config file in the background and return immediately. - if !configExists { - defer cancel() - return fetchCfg() - } - - go func() { - defer cancel() - if err := fetchCfg(); err != nil { - ctx.Verbosef("Failed to fetch config file %v: %v\n", configName, err) - } - }() - return nil -} - func loadEnvConfig(ctx Context, config *configImpl, bc string) error { if bc == "" { return nil @@ -368,12 +283,14 @@ func NewConfig(ctx Context, args ...string) Config { bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG") if bc != "" { - if err := fetchEnvConfig(ctx, ret, bc); err != nil { - ctx.Verbosef("Failed to fetch config file: %v\n", err) - } 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 { @@ -520,6 +437,11 @@ func NewConfig(ctx Context, args ...string) Config { ret.environ.Set("ANDROID_JAVA11_HOME", java11Home) ret.environ.Set("PATH", strings.Join(newPath, string(filepath.ListSeparator))) + // b/286885495, https://bugzilla.redhat.com/show_bug.cgi?id=2227130: some versions of Fedora include patches + // to unzip to enable zipbomb detection that incorrectly handle zip64 and data descriptors and fail on large + // zip files produced by soong_zip. Disable zipbomb detection. + ret.environ.Set("UNZIP_DISABLE_ZIPBOMB_DETECTION", "TRUE") + if ret.MultitreeBuild() { ret.environ.Set("MULTITREE_BUILD", "true") } @@ -1374,18 +1296,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 |